| Tenouk C & C++ | MFC Home | Modeless Dialog & Windows Common Dialogs 1 | Menus, Key Acc., Rich Edit & Property Sheets 1 | Download | Site Index |


 

 

 

 

 

Module 6a:

The Modeless Dialog and Windows Common Dialogs 2

 

 

 

 

 

This is a continuation from the previous module... Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below:

  1. The CFormView Class: A Modeless Dialog Alternative

  2. The Windows Common Dialogs

  3. Using the CFileDialog Class Directly

  4. Deriving from the Common Dialog Classes

  5. Nested Dialogs

  6. A CFileDialog Example: MYMFC10

  7. Other Customization for CfileDialog

 

 

 

The CFormView Class: A Modeless Dialog Alternative

 

If you need an application based on a single modeless dialog, the CFormView class will save you a lot of work and will be discussed in another Module together with the CDocument class, because the CFormView class is most useful when coupled with it.

 

The Windows Common Dialogs

 

Windows provides a group of standard user interface dialogs, and these are supported by the MFC library classes. You are probably familiar with all or most of these dialogs because so many Windows-based applications, including Visual C++, already use them. All the common dialog classes are derived from a common base class, CCommonDialog. A list some of the COMDLG32 classes is shown in the following table.

 

Class

Purpose

CColorDialog

Allows the user to select or create a color.

CFileDialog

Allows the user to open or save a file.

CFindReplaceDialog

Allows the user to substitute one string for another.

CPageSetupDialog

Allows the user to input page measurement parameters.

CFontDialog

Allows the user to select a font from a list of available fonts.

CPrintDialog

Allows the user to set up the printer and print a document.

 

Table 3: Some of the COMDLG32 classes.

 

Here's one characteristic that all common dialogs share: they gather information from the user, but they don't do anything with it. The file dialog can help the user select a file to open, but it really just provides your program with the pathname, your program must make the call that opens the file. Similarly, a font dialog fills in a structure that describes a font, but it doesn't create the font.

 

Using the CFileDialog Class Directly

 

Using the CFileDialog class to open a file is easy. The following code opens a file that the user has selected through the dialog:

 

CFileDialog dlg(TRUE, "bmp", "*.bmp");

if (dlg.DoModal() == IDOK)

{

    CFile file;

    VERIFY(file.Open(dlg.GetPathName(), CFile::modeRead));

}

 

The first constructor parameter (TRUE) specifies that this object is a "File Open" dialog instead of a "File Save" dialog. The default file extension is bmp, and *.bmp appears first in the filename edit box. The CFileDialog::GetPathName function returns a CString object that contains the full pathname of the selected file.

 

Deriving from the Common Dialog Classes

 

Most of the time, you can use the common dialog classes directly. If you derive your own classes, you can add functionality without duplicating code. Each COMDLG32 dialog works a little differently, however. The next example is specific to the file dialog, but it should give you some ideas for customizing the other common dialogs. In the early editions of this book, the MYMFC10 example dynamically created controls inside the standard file dialog. That technique doesn't work in Win32, but the nested dialog method described here has the same effect.

 

Nested Dialogs

 

Win32 provides a way to "nest" one dialog inside another so that multiple dialogs appear as one seamless whole. You must first create a dialog resource template with a "hole" in it, typically a group box control, with the specific child window ID stc32 (= 0x045f). Your program sets some parameters that tell COMDLG32 to use your template. In addition, your program must hook into the COMDLG32 message loop so that it gets first crack at selected notifications. When you're done with all of this, you'll notice that you have created a dialog window that is a child of the COMDLG32 dialog window, even though your template wraps COMDLG32's template.

This sounds difficult, and it is unless you use MFC. With MFC, you build the dialog resource template as described above, derive a class from one of the common dialog base classes, add the class-specific connection code in OnInitDialog(), and then happily use ClassWizard to map the messages that originate from your template's new controls.

Windows NT 3.51 uses an earlier version of the common dialogs DLL that does not support the new Windows namespace feature. The nested dialog technique illustrated in the MYMFC10 example won't work with the Windows NT 3.51 version of the file dialog.

 

A CFileDialog Example: MYMFC10

 

In this example, you will derive a class CMymfc10Dialog that adds a working Delete All Matching Files button to the standard file dialog. It also changes the dialog's title and changes the Open button's caption to Delete (to delete a single file). The example illustrates how you can use nested dialogs to add new controls to standard common dialogs. The new file dialog is activated as in the previous examples, by pressing the left mouse button when the mouse cursor is in the view window. Because you should be gaining skill with Visual C++, the following steps won't be as detailed as those for the earlier examples. Figure 23 shows what the dialog will look like.

 

The MYMFC10’s Delete File dialog in action.

 

Figure 23: The MYMFC10’s Delete File dialog in action.

 

Follow these steps to build the MYMFC10 application:

 

Run AppWizard to produce \mfcproject\mymfc10 project (change accordingly to directory that you have designated for your project). Accept all the defaults but two: select Single Document and deselect Printing And Print Preview and ActiveX Controls. The options and the default class names are shown in the next graphic.

 

MYMFC10 project summary.

 

Figure 24: MYMFC10 project summary.

 

Use the dialog editor to create a dialog resource. Make the dialog box about 3-by-5 inches, and use the ID IDD_FILESPECIAL. Set the dialog's Style property to Child, its Border property to None and select its Clip Siblings and Visible properties. Delete the OK and Cancel button.

 

Modifying the dialog properties.

 

Figure 25: Modifying the dialog properties.

 

Create a button with ID IDC_DELETE and a group box with ID stc32 (=0x045f in hexadecimal), as shown here.

 

Modifying push button’s properties.

 

Figure 26: Modifying push button’s properties.

 

Modifying group box’s properties.

 

Figure 27: Modifying group box’s properties.

 

Check your work by choosing Resource Symbols from the Visual C++ View menu. You should see a symbol list like the one shown in the graphic below.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

----------------------------------------------------------

Viewing project’s resource symbols.

 

Figure 28: Viewing and adding project’s resource symbols.

 

MYMFC10 resource symbols.

 

Figure 29: MYMFC10 resource symbols.

 

Use ClassWizard to create the CSpecialFileDialog class.

 

Creating the CSpecialFileDialog class.

 

Figure 30: Creating the CSpecialFileDialog class.

 

Fill in the New Class dialog, as shown here, and then click the Change button.

 

CSpecialFileDialog class information.

 

Figure 31: CSpecialFileDialog class information.

 

Change the names to SpecFileDlg.h and SpecFileDlg.cpp. Unfortunately, we cannot use the Base Class drop-down list to change the base class to CFileDialog, as that would decouple our class from the IDD_FILESPECIAL template. We have to change the base class by hand.

 

Changing CSpecialFileDialog class’s header and implementation file names.

 

Figure 32: Changing CSpecialFileDialog class’s header and implementation file names.

 

Edit the file SpecFileDlg.h. Change the line:

 

class CSpecialFileDialog : public CDialog

 

To

 

class CSpecialFileDialog : public CFileDialog

 

Visual C++ MFC code segment

 

Listing 17.

 

Add the following two public data members:

 

CString   m_strFilename;

BOOL     m_bDeleteAll;

 

Visual C++ MFC code segment

 

Listing 18.

 

Finally, edit the constructor declaration:

 

CSpecialFileDialog(BOOL bOpenFileDialog,

    LPCTSTR lpszDefExt = NULL,

    LPCTSTR lpszFileName = NULL,

    DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,

    LPCTSTR lpszFilter = NULL,

    CWnd* pParentWnd = NULL);

 

Visual C++ MFC code segment

 

Listing 19.

 

 

Replace CDialog with CFileDialog in SpecFileDlg.h. Choose Replace from Visual C++'s Edit menu, and replace this name globally.

 

Replacing CDialog with CFileDialog in SpecFileDlg.h.

 

Figure 33: Replacing CDialog with CFileDialog in SpecFileDlg.h.

 

Edit the CSpecialFileDialog constructor in SpecFileDlg.cpp. The derived class destructor must invoke the base class constructor and initialize the m_bDeleteAll data member. In addition, it must set some members of the CFileDialog base class data member m_ofn, which is an instance of the Win32 OPENFILENAME structure. The Flags and lpTemplateName members control the coupling to your IDD_FILESPECIAL template, and the lpstrTitle member changes the main dialog box title. Edit the constructor as follows:

 

CSpecialFileDialog::CSpecialFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, DWORD dwFlags,

        LPCTSTR lpszFilter, CWnd* pParentWnd) : CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)

{

    //{{AFX_DATA_INIT(CSpecialFileDialog)

        // NOTE: the ClassWizard will add member initialization here

    //}}AFX_DATA_INIT

    m_ofn.Flags |= OFN_ENABLETEMPLATE;

    m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILESPECIAL);

    m_ofn.lpstrTitle = "Delete File";

    m_bDeleteAll = FALSE;

}

 

Visual C++ MFC code segment

 

Listing 20.

 

Map the WM_INITDIALOG message in the CSpecialFileDialog class. The OnInitDialog() member function needs to change the common dialog's Open button caption to Delete. The child window ID is IDOK.

 

Mapping the WM_INITDIALOG message in the CSpecialFileDialog class.

 

Figure 34: Mapping the WM_INITDIALOG message in the CSpecialFileDialog class.

 

BOOL CSpecialFileDialog::OnInitDialog()

{

 

       BOOL bRet = CFileDialog::OnInitDialog();

       if (bRet == TRUE)

       {

              GetParent()->GetDlgItem(IDOK)->SetWindowText("Delete");

       }

       return bRet;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Visual C++ MFC code segment

 

Listing 21.

 

Map the new IDC_DELETE button (Delete All Matching Files) in the CSpecialFileDialog class.

 

Mapping the new IDC_DELETE button in the CSpecialFileDialog class.

 

Figure 35: Mapping the new IDC_DELETE button in the CSpecialFileDialog class.

 

The OnDelete() member function sets the m_bDeleteAll flag and then forces the main dialog to exit as if the Cancel button had been clicked. The client program (in this case, the view) gets the IDCANCEL return from DoModal() and reads the flag to see whether it should delete all files. Here is the function:

 

 void CSpecialFileDialog::OnDelete()

{

    m_bDeleteAll = TRUE;

    // 0x480 is the child window ID of the File Name edit control

    // (as determined by SPY++)

    GetParent()->GetDlgItem(0x480)->GetWindowText(m_strFilename);

    GetParent()->SendMessage(WM_COMMAND, IDCANCEL);

}

 

Visual C++ MFC code segment

 

Listing 22.

 

Add code to the virtual OnDraw() function in file mymfc10View.cpp. The CMymfc10View OnDraw() function which skeleton was generated by AppWizard should be coded as follows to prompt the user to press the mouse button:

 

void Cmymfc10View::OnDraw(CDC* pDC)

{

    pDC->TextOut(30, 30, "Press the left mouse button lol! ");

}

 

Visual C++ MFC code segment

 

Listing 23.

 

Add the OnLButtonDown() message handler to the Cmymfc10View class. Use ClassWizard to create the message handler for WM_LBUTTONDOWN.

 

Adding the OnLButtonDown() message handler to the Cmymfc10View class.

 

Figure 36: Adding the OnLButtonDown() message handler to the Cmymfc10View class.

 

And then edit the code as follows:

 

void Cmymfc10View::OnLButtonDown(UINT nFlags, Cpoint point)

{

    CspecialFileDialog dlgFile(TRUE, NULL, "*.obj");

    Cstring strMessage;

    int nModal = dlgFile.DoModal();

    if ((nModal == IDCANCEL) && (dlgFile.m_bDeleteAll))

    {

        strMessage.Format("Are you very sure you want to delete all %s files? ", dlgFile.m_strFilename);

        if (AfxMessageBox(strMessage, MB_YESNO) == IDYES)

        {

         HANDLE h;

         WIN32_FIND_DATA fData;

         while((h = ::FindFirstFile(dlgFile.m_strFilename, &fData)) != (HANDLE)0xFFFFFFFF)

            { // no MFC equivalent

                if (::DeleteFile(fData.cFileName) == FALSE)

                {

                    strMessage.Format("Unable to delete file %s\n", fData.cFileName);

                    AfxMessageBox(strMessage);

                    break;

                }

            }

        }

    }

    else if (nModal == IDOK)

    {

        Cstring strSingleFilename = dlgFile.GetPathName();

        strMessage.Format("Are you very sure you want to delete %s?", strSingleFilename);

        if (AfxMessageBox(strMessage, MB_YESNO) == IDYES)

        {

            Cfile::Remove(strSingleFilename);

        }

    }

}

 

Visual C++ MFC code segment

 

Listing 24.

 

Remember that common dialogs just gather data. Since the view is the client of the dialog, the view must call DoModal() or the file dialog object and then figure out what to do with the information returned. In this case, the view has the return value from DoModal() (either IDOK or IDCANCEL) and the value of the public m_bDeleteAll data member, and it can call various CfileDialog member functions such as GetPathName(). If DoModal() returns IDCANCEL and the flag is TRUE, the function makes the Win32 file system calls necessary to delete all the matching files. If DoModal() returns IDOK, the function can use the MFC Cfile() functions to delete an individual file.

 

Using the global AfxMessageBox() function is a convenient way to pop up a simple dialog that displays some text and then queries the user for a Yes/No answer. Finally add the include the statement:

 

#include "SpecFileDlg.h"

 

After the line:

 

#include "mymfc10View.h"

 

Visual C++ MFC code segment

 

Listing 25.

 

Build and test the application. Build and run MYMFC10. Pressing the left mouse button should bring up the Delete File dialog, and you should be able to use it to navigate through the disk directory and to delete files. Be careful not to delete your important source files!

 

MYMFC10 program output.

 

Figure 37: MYMFC10 program output.

 

MYMFC10 program output, when left mouse button is clicked, launching a delete file dialog.

 

Figure 38: MYMFC10 program output, when left mouse button is clicked, launching a delete file dialog.

 

Other Customization for CfileDialog

 

In the MYMFC10 example, you added a pushbutton to the dialog. It’s easy to add other controls too. Just put them in the resource template, and if they are standard Windows controls such as edit controls or list boxes, you can use ClassWizard to add data members and DDX/DDV code to your derived class. The client program can set the data members before calling DoModal(), and it can retrieve the updated values after DoModal() returns. Even if you don’t use nested dialogs, two windows are still associated with a CfileDialog object. Suppose you have overridden OnInitDialog() in a derived class and you want to assign an icon to the file dialog. You must call CWnd::GetParent to get the top-level window, just as you did in the MYMFC10 example. Here’s the code:

 

HICON hIcon = AfxGetApp()->LoadIcon(ID_MYICON);

GetParent()->SetIcon(hIcon, TRUE);   // Set big icon

GetParent()->SetIcon(hIcon, FALSE);  // Set small icon

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

  1. MSDN MFC 7.0 class library online documentation.

  2. MSDN MFC 9.0 class library online documentation - latest version.

  3. Porting & Migrating your older programs.

  4. MSDN Library

  5. DCOM at MSDN.

  6. COM+ at MSDN.

  7. COM at MSDN.

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | Modeless Dialog & Windows Common Dialogs 1 | Menus, Key Acc., Rich Edit & Property Sheets 1 | Download | Site Index |