[MFC] Creating (non-)modal dialog boxes and possible problems

s1. Create a new project

s2. Find Dialog in the resource view, right-click and insert to generate a new Dialog. Repeat the operation to generate another one

s3, drag two buttons from the main Dialog

s4. Create a modal dialog box. Double-click to create the first button

Note 1

Here, a CDialog object named dlg is created and associated to the dialog template with the resource identifier ID of IDD_DIALOG1. Then you can use the methods and properties of the dlg object to operate the dialog box and display the dialog box. The DoModal() method displays the dialog box (dlg) as a modal dialog box.

Since the modal window program will stay at dlg.DoModal(), the dlg object will not be destroyed before the window is closed! ! ! ! (different from non-modal)

Run the test.

s5, add a class to the modal window

Note 2

The base class here can be CDialogEx or CDialog.

CDialogEx appeared after VS2003, but not in VC++ 6.0. This class is an extension class of CDialog, and the base class is CDialog.

However, if the main window class inherits CDialog and the CMoTi class inherits CDialogEx, an error may be reported during operation. Just change everything to ex.

No error will be reported unless the above situation occurs.

s6. Modify the previous Button response event code

Run and test

s7. After having the class, you can add interactive operations to the dialog box

Drag an edit box, right-click the window and select Class Wizard Virtual Function

Add initialization in the virtual function. The popularity will not affect the operation. Patients with obsessive-compulsive disorder can add the header file resource.h

have a test

s8. Start operating the non-modal window

Add edit box, right-click window, add class

s9, double-click to create a non-modal Button

Add code (can be improved. Repeatedly clicking the create button will cause an error. This can be avoided by adding the class member isCreate(Bool).)

Note 3

The class object fmt_dlg needs to be defined outside the function. Since the non-modal window does not block when the code is running, if the object is created inside, it will be destroyed instantly. The window crashes. As shown below (error demonstration).

Note 4: An error occurs when a non-modal window is repeatedly created

As shown in the figure below, a non-modal window has been created, but when it is created again, an exception occurs. Reason: Only one object can be created.

In MFC, create a dialog box instance by calling the Create() method. However, each dialog box instance can only be displayed once after creation. Attempting to call the Create() method again to create an instance of the same dialog box will throw an error.

If there are two calls to fmt_dlg.Create(IDD_DIALOG2) in the code, the second call will cause the program to throw an exception or error. This is because the first dialog instance has already been created and displayed and cannot be created again.

If you need to display the same dialog box multiple times while the program is running, consider using the DoModal() method instead of the Create() method. The DoModal() method will be executed until the dialog box is closed, and then the program can call the DoModal() method again to display the dialog box.

Also, if you do need to create multiple instances of the same type of dialog box, consider using different variables to save and manage each instance. For example, declare multiple dialog class objects and create and display different instances respectively.

In summary, avoid calling the Create() method multiple times to create instances of the same dialog box, as this can lead to errors.

s10, modify code

Since new is used, it needs to be deleted at the end of the program to recycle resources.

Right click on the non-modal dialog -> Class Wizard and add a virtual function

Note 5 PostNcDestroy() Virtual function, used to perform some cleanup operations after the dialog box is destroyed.

When a dialog box is destroyed (such as the dialog box is closed), the MFC framework automatically calls the PostNcDestroy() function. This function will be called immediately after the non-client area of the dialog box is destroyed to perform some aftermath work, such as releasing resources, deleting objects, etc.

s11, rewrite the PostNcDestroy() function

s12. Add the DestroyWindow() function (it is not recommended to add it here, adding it will report an error TODO: to be improved)

The DestroyWindow() function is a Windows API function used to destroy the specified window. When this function is called, it sends a WM_DESTROY message to the window to invalidate the window and remove keyboard focus from the window. Additionally, this function destroys the window’s menu, timer, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain). In a non-modal dialog box, calling OnOk() or OnCancel function (EndDialog) will not trigger the WM_DESTROY message, so the above function will not be called. This is why many books emphasize that modeless dialog boxes should not be destroyed by calling OnOk() or OnCancel function but should be destroyed by calling DestroyWindow function.

After adding point 6, the above program will crash because:

#include "CFMoTiDlg.h"
void CDialogCreatePraDlg::OnBnClickedButton2()
{
// TODO: Add control notification handler code here
static CFMoTiDlg* pfmt_dlg = NULL;
if (!pfmt_dlg) {
pfmt_dlg = new CFMoTiDlg;
pfmt_dlg->Create(IDD_DIALOG2,this);
}
pfmt_dlg->ShowWindow(SW_SHOW);
}

In this code, we statically declare a pointer variable, which points to a memory address of the CFMoTiDlg class new when it is first run. When a non-modal window is closed, the DestroyWindow() function recycles all resources of this class, and the pfmt_dlg pointer becomes invalid, so , the program will crash directly when running the creation again.