现在的位置: 首页 > 综合 > 正文

《MFC那点事儿》の模态对话框和非模态对话框

2013年08月02日 ⁄ 综合 ⁄ 共 2020字 ⁄ 字号 评论关闭

MFC中有两种类型的对话框:模态对话框和非模态对话框。

模态对话框是指当其显示时,程序会暂停执行,直到关闭这个模态对话框后,才能继续执行程序中其他任务。非模态对话框是指当其显示时,允许转而执行程序中其他任务,而不用关闭这个对话框。

 

模态对话框的创建:

创建模态对话框需要调用CDialog类的成员函数:DoModal,该函数的功能是创建并显示一个模态对话框,其返回值将作为CDialog类的另一个成员函数:EndDialog的参数,后者的功能是关闭模态对话框。一般显示模态对话框的实现代码如下:

void CASCEView::OnDialog()

{

         CASCEDlg dlg;

         dlg.DoModal();

}

 

非模态对话框的创建:

要创建非模态对话框就需要利用CDialog类的Create成员函数,该函数有以下两种形式的声明:

virtual BOOL Create(

   LPCTSTR lpszTemplateName,

   CWnd* pParentWnd = NULL

);

virtual BOOL Create(

   UINT nIDTemplate,

   CWnd* pParentWnd = NULL

);

有上可知,CDialog::Create函数的第一个参数可以是对话框资源的IDnIDTemplate),或者也可以是对话框模板的名称(lpszTemplateName);而第二个参数指定了对话框的父窗口,如果其值是NULL,则对话框的父窗口就是主应用程序窗口。

当利用Create函数创建非模态对话框时,我们还需要接着调用ShowWindow函数来将这个对话框显示出来;而利用DoModal创建的模态对话框之所以不用,是因为DoModal函数本身就有显示模态对话框的作用。同时我们不能像模态对话框那样将对话框定义成对象,如下代码是显示不出非模态对话框的:

void CASCEView::OnDialog()

{

         CASCEDlg dlg;

         dlg.Create(IDD_DIALOG1, this);

         dlg.ShowWindow(SW_SHOW);

}

因为这里创建的非模态对话框对象dlg是一个局部对象,当程序执行时,会依次执行各条代码,当OnDialog函数执行结束时,dlg这个对象的生命周期也就玩玩了,它就会销毁与之相关联的对话框资源,对话框自然就显示不出来啦!而模态对话框之所以能够显示,是因为当执行到调用DoModal函数以显示模态对话框时,程序就会暂停执行,直到模态对话框关闭之后,程序才继续向下执行。而这之前,dlg还没销毁。

因此,在创建非模态对话框时,不能将对话框对象定义成局部变量,解决方法有二:一是把对话框对象定义成CASCEView类的成员变量;二是把它定义成指针,在堆上分配内存,如下:

void CASCEView::OnDialog()

{

         CASCEDlg *pDlg = new CASCEDlg;

         pDlg->Create(IDD_DIALOG1, this);

         pDlg->ShowWindow(SW_SHOW);

}

但是这又引入了新的问题:我们必须释放pDlg占用的资源,否则会造成内存泄漏!况且这里pDlg还是一个局部指针变量,当它的生命周期结束时,在程序中就无法再引用它所指向的那块内存了。解决方法同样有两个:一是将pDlg定义成CASCEView类的成员变量,然后在CASCEView类的析构函数中调用delete函数释放它指向的内存;二是在CASCEDlg类中重载PostNcDestroy虚函数,释放this指针指向的内存:

void CASCEDlg::PostNcDestroy()

{

         delete this;

         CDialog::PostNcDestroy();

}

 

还有一点需要注意的是:当单击对话框上的默认OK按钮时,两种对话框都会消失。但对于模态对话框而言,此时对话框窗口对象被销毁了;而对非模态对话框来说,对话框窗口对象并未被销毁,只是隐藏起来而已。

在非模态对话框中单击OK按钮后,程序会调用基类CDialogOnOK函数,这是一个虚函数,后者又会调用EndDialog函数,这个函数用于终止模态对话框,但对于非模态对话框,这个函数只是使对话框窗口不可见,并不销毁它。因此,对非模态对话框来说,如果有一个ID值为IDOK的按钮,就必须重写基类的OnOK虚函数,并在重写的函数中调用DestroyWindow函数,以完成销毁对话框的工作,同时注意不要再调用基类的OnOK函数。同理,如果非模态对话框中有一个ID值为IDCANCEL的按钮,也必须重写基类的OnCancel虚函数,并在重写的函数中调用DestroyWindow函数,销毁对话框,同时注意不要再调用基类的OnCancel函数了。

 

 

 

 

 

抱歉!评论已关闭.