2024年4月2日发(作者:)
模态对话框和非模态对话框的区别
假设对话框类名为:CTestDlg
1,如果是模态对话框:
CTestDlg ctd;//创建该对话框对像
le();
2,如果是非模态的:
CTestDlg *p_ctd= new CTestDlg();//创建对话框的对像指针
p_ctd->Create(IDD_READING,this);//指针调用Create()函数,ID号为对话框
的.
p_ctd->ShowWindow(SW_SHOWNA);//()中的参数可以用来改变对话框的显示模式
(具体参见MSDN中ShowWindow()函数)
模态对话框创建后一定要在用户单击完对话框上的"确定"或"取消"或"关闭",也
就是对它进行了响应并关闭后,程序才能继续执行.
而非模态的则是创建完后程序可以继续执行,对话框可以成为后台对话框.所以
也可以用函数来关闭
p_ctd->DestroyWindow();
模态对话框就是指那种“显示出来就不可以点选位于其下面的对话框”的对话
框;反之的就是非模态对话框。
两者的区别:
一. 非模态对话框的模板必须具有Visible风格(Visible=True),否则对话框将
不可见,而模态对话框则无需设置该项风格。在实际编程中更加保险的办法是调
用CWnd::ShowWindow(SW_SHOW)来显示对话框,而不管对话框是否具有Visible
风格。
二. 非模态对话框对象是用new操作符来动态创建的,而不是以成员变量的形式
嵌入到别的对象中或以局部变量的形式构建的。通常应在对话框的拥有者窗口类
内声明一个指向对话框类的指针成员变量,通过该指针可访问对话框对象。
三. 通过调用CDialog::Create函数来启动对话框,而不是CDialog::DoModal,
这是两者之间区别的关键所在。由于Create函数不会启动新的消息循环,对话
框与应用程序共用同一个消息循环,这样对话框就不会垄断用户输入。Create
在显示了对话框后就立即返回,而DoModal是在对话框被关闭后才返回的。由于
在Create返回后,不能确定对话框是否已关闭,这样也就无法确定对话框对象
的生存期,因此只好在堆栈中构建对话框对象,而不能以局部变量的形式来构建
之。
四. 必须调用CWnd::DestroyWindow而不是CDialog::EndDialog来关闭非模态
对话框。调用CWnd::DestroyWindow是直接删除窗口的一般方法。由于缺省的
CDialog::OnOK和CDialog::OnCancel函数均调用EndDialog,故程序员必须编
写自己的OnOK和OnCancel函数并且在函数中调用DestroyWindow来关闭对话
框。
五. 因为是用new操作符构建非模态对话框对象,因此必须在对话框关闭后,用
delete操作符删除对话框对象。在屏幕上一个窗口被删除后,框架会调用
CWnd::PostNcDestroy,这是一个虚拟函数,程序可以在该函数中完成删除窗口
对象的工作,具体代码如下
void CModelessDialog::PostNcDestroy
{delete this; //删除对象}
这样,在删除屏幕上的对话框后,对话框对象将被自动删除。拥有者就不必显式
地调用delete来删除对话框对象了。
六. 必须有一个标志表明非模态对话框是否打开的。这样做的原因是用户有可能
在打开一个模态对话框的情况下,又一次选择打开命令。程序根据标志来决定是
打开一个新的对话框,还是仅仅把原来打开的对话框激活。通常可以用拥有者窗
口中的指向对话框对象的指针作为这种标志,当对话框关闭时,给该指针赋NULL
值,以表明对话框对象已不存在了。
例如:
创建模态对话框
CTestDlg dlg;
l();
创建非模态对话框
CTestDlg * dlg = new CTestDlg;
dlg->Create(IDD_TEST_DLG);
dlg->ShowWindow(SW_SHOW);
使用非模态对话框与使用模态对话框相似,但是也有一些重要的区别:
首先,非模态对话框通常包含一个标题列和一个系统菜单按钮。当您在
Developer Studio中建立对话框时,这些是内定选项。用于非模态对话框的对
话框模板中的STYLE叙述形如:
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
标题列和系统菜单允许使用者,使用鼠标或者键盘将非模态对话框移动到另一个
显示区域。对于模态对话框,您通常无须提供标题列和系统菜单,因为使用者不
能在其下面的窗口中做任何其它的事情。
第二项重要的区别是:注意,在我们的范例STYLE叙述中包含有WS_VISIBLE样
式。在 Developer Studio中,从「Dialog Properties」对话框的「More Styles」
页面卷标中选择此选项。如果省略了WS_VISIBLE,那么您必须在CreateDialog
呼叫之后呼叫ShowWindow:
hDlgModeless = CreateDialog ( . . . ) ;
ShowWindow (hDlgModeless, SW_SHOW) ;
如果您既没有包含WS_VISIBLE样式,又没有呼叫ShowWindow,那么非模态对话
框将不会被显示。如果忽略这个事实,那么习惯于模态对话框的程序写作者在第
一次试图建立非模态对话框时,经常会出现问题。
第三项区别:与模态对话框和消息框的消息不同,非模态对话框的消息要经过程
序式的消息队列。要将这些消息传送给对话框窗口消息处理程序,则必须改变消
息队列。方法如下:当您使用CreateDialog建立非模态对话框时,应该将从呼
叫中传回的对话框句柄储存在一个整体变量(如hDlgModeless)中,并将消息
循环改变为:
while (GetMessage (&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
如果消息是发送给非模态对话框的,那么IsDialogMessage将它发送给对话框中
窗口消息处理程序,并传回TRUE(非0);否则,它将传回FALSE(0)。只有
hDlgModeless为0或者消息不是该对话框的消息时,才必须呼叫
TranslateMessage和DispatchMessage函数。如果您将键盘快捷键用于您的程
序窗口,那么消息循环将如下所示:
while (GetMessage (&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))
{
if (!TranslateAccelerator (hwnd, hAccel, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
}
由于整体变量被初始化为0,所以hDlgModeless将为0,直到建立对话框为止,
从而保证不会使用无效的窗口句柄来呼叫IsDialogMessage。在清除非模态对话
框时,您也必须注意这一点,正如最后一点所说明的。
hDlgModeless变量也可以由程序的其它部分使用,以便对非模态对话框是否存
在加以验证。例如,程序中的其它窗口可以在hDlgModeless不等于0时给对话
框发送消息。
最后一项重要的区别:使用DestroyWindow而不是EndDialog来结束非模态对话
框。当您呼叫DestroyWindow后,将hDlgModeless整体变量设定为0。
使用者习惯于从系统菜单中选择「Close」来结束非模态对话框。尽管启用了
「Close」选项,Windows内的对话框窗口消息处理程序并不处理WM_CLOSE消息。
您必须自己在对话框程序中处理它:
case WM_CLOSE :
DestroyWindow (hDlg) ;
hDlgModeless = NULL ;
break ;
注意这两个窗口句柄之间的区别:DestroyWindow的hDlg参数是传递给对话框
程序的参数;hDlgModeless是从CreateDialog传回的整体变量,程序在消息循
环内检验它。
您也可以允许使用者使用按键来关闭非模态对话框,处理方式与处理WM_CLOSE
消息一样。对话框必须传回给建立它的窗口之任何数据都可以储存在整体变量
中。如果不喜欢使用整体变量,那么您也可以用CreateDialogParam来建立非模
态对话框,并按前面介绍的方法让它储存一个结构指针。
发布评论