1
与模态对话框不同,非模态对话框不垄断用户的输入,用户打开非模态对话框后,仍然可以与其它界面进
行交互。
非模态对话框的设计与模态对话框基本类似,也包括设计对话框模板和设计 CDialog 类的派生类两部分。
但是,在对话框的创建和删除过程中,非模态对话框与模态对话框相比有下列不同之处:
非模态对话框的模板必须具有 Visible 风格,否则对话框将不可见,而模态对话框则无需设置该项
风格。更保险的办法是调用 CWnd::ShowWindow(SW_SHOW)来显示对话框,而不管对话框是否
具有 Visible 风格。
非模态对话框对象是用 new 操作符在堆中动态创建的,而不是以成员变量的形式嵌入到别的对象
中或以局部变量的形式构建在堆栈上。通常应在对话框的拥有者窗口类内声明一个指向对话框类
的指针成员变量,通过该指针可访问对话框对象。
通过调用 CDialog::Create 函数来启动对话框,而不是 CDialog::DoModal,这是模态对话框的关
键所在。由于 Create 函数不会启动新的消息循环,对话框与应用程序共用同一个消息循环,这样
对话框就不会垄断用户的输入。Create 在显示了对话框后就立即返回,而 DoModal 是在对话框
被关闭后才返回的。众所周知,在 MFC 程序中,窗口对象的生存期应长于对应的窗口,也就是
说,不能在未关闭屏幕上窗口的情况下先把对应的窗口对象删除掉。由于在 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 值,以表明对话框对象已不存在了。
提示:在 C++编程中,判断一个位于堆中的对象是否存在的常用方法是判断指向该对象的指针是否为空。
这种机制要求程序员将指向该对象的指针初始化为 NULL 值,在创建对象时将返回的地址赋给该指针,而
在删除对象时将该指针置成 NULL 值。
根据上面的分析,我们很容易把 Register 程序中的登录数据对话框改成非模态对话框。这样做的好处
在于如果用户在输入数据时发现编辑视图中有错误的数据,那么不必关闭对话框,就可以在编辑视图中进
行修改。
请读者按下面几步操作:
在登录数据对话框模板的属性对话框的 More Styles 页中选择 Visible 项。
在 RegisterView.h 头文件的 CRegisterView 类的定义中加入
public:
CRegisterDialog* m_pRegisterDlg;