📄 chap5_4.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>5.4 非模态对话框</title>
</head>
<body link="#3973DE" alink="#3973DE" background="../../bg.gif">
<font SIZE="5"><b><div align="center"><center>
<table border="0" width="85%" cellspacing="0" cellpadding="0" bgcolor="#FFFFFF">
<tr>
</b><td><div align="center"><center><table border="0" width="615" cellpadding="0"
cellspacing="0" height="20">
<tr>
<td width="377" bgcolor="#15397D" height="20"></td>
<td width="238" bgcolor="#000000" height="20"><p align="right"></font><a
href="../../vc.htm"><span style="text-decoration: none"><font color="#FFFFFF">电脑报Visual
C++网络教程</font></span></a></td>
</tr>
</table>
</center></div><font FACE="Times New Roman" SIZE="3"><b><p ALIGN="CENTER"></b></font><font
FACE="Times New Roman" size="4" color="#3973DE">5.4 </font><font size="4" color="#3973DE">非模态对话框</font><font
FACE="Times New Roman" size="4"></p>
<p ALIGN="JUSTIFY"></font><span style="font-size: 9pt"><font color="#3973DE">5.4.1
非模态对话框的特点</font></span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">与模态对话框不同,非模态对话框不垄断用户的输入,用户打开非模态对话框后,仍然可以与其它界面进行交互。</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">非模态对话框的设计与模态对话框基本类似,也包括设计对话框模板和设计CDialog类的派生类两部分。但是,在对话框的创建和删除过程中,非模态对话框与模态对话框相比有下列不同之处:</span></p>
<ul>
<li><p ALIGN="JUSTIFY"><span style="font-size: 9pt">非模态对话框的模板必须具有Visible风格,否则对话框将不可见,而模态对话框则无需设置该项风格。更保险的办法是调用CWnd::ShowWindow(SW_SHOW)来显示对话框,而不管对话框是否具有Visible风格。</span></p>
</li>
<li><p ALIGN="JUSTIFY"><span style="font-size: 9pt">非模态对话框对象是用new操作符在堆中动态创建的,而不是以成员变量的形式嵌入到别的对象中或以局部变量的形式构建在堆栈上。通常应在对话框的拥有者窗口类内声明一个指向对话框类的指针成员变量,通过该指针可访问对话框对象。</span></p>
</li>
<li><p ALIGN="JUSTIFY"><span style="font-size: 9pt">通过调用CDialog::Create函数来启动对话框,而不是CDialog::DoModal,这是模态对话框的关键所在。由于Create函数不会启动新的消息循环,对话框与应用程序共用同一个消息循环,这样对话框就不会垄断用户的输入。Create在显示了对话框后就立即返回,而DoModal是在对话框被关闭后才返回的。众所周知,在MFC程序中,窗口对象的生存期应长于对应的窗口,也就是说,不能在未关闭屏幕上窗口的情况下先把对应的窗口对象删除掉。由于在Create返回后,不能确定对话框是否已关闭,这样也就无法确定对话框对象的生存期,因此只好在堆中构建对话框对象,而不能以局部变量的形式来构建之。</span></p>
</li>
<li><p ALIGN="JUSTIFY"><span style="font-size: 9pt">必须调用CWnd::DestroyWindow而不是CDialog::EndDialog来关闭非模态对话框。调用CWnd::DestroyWindow是直接删除窗口的一般方法。由于缺省的CDialog::OnOK和CDialog::OnCancel函数均调用EndDialog,故程序员必须编写自己的OnOK和OnCancel函数并且在函数中调用DestroyWindow来关闭对话框。</span></p>
</li>
<li><p ALIGN="JUSTIFY"><span style="font-size: 9pt">因为是用new操作符构建非模态对话框对象,因此必须在对话框关闭后,用delete操作符删除对话框对象。在屏幕上一个窗口被删除后,框架会调用CWnd::PostNcDestroy,这是一个虚拟函数,程序可以在该函数中完成删除窗口对象的工作,具体代码如下<br>
void CModelessDialog::PostNcDestroy<br>
{<br>
delete this; //删除对象本身<br>
}<br>
这样,在删除屏幕上的对话框后,对话框对象将被自动删除。拥有者对象就不必显式的调用delete来删除对话框对象了。</span></p>
</li>
<li><p ALIGN="JUSTIFY"><span style="font-size: 9pt">必须有一个标志表明非模态对话框是否是打开的。这样做的原因是用户有可能在打开一个模态对话框的情况下,又一次选择打开命令。程序根据标志来决定是打开一个新的对话框,还是仅仅把原来打开的对话框激活。通常可以用拥有者窗口中的指向对话框对象的指针作为这种标志,当对话框关闭时,给该指针赋NULL值,以表明对话框对象已不存在了。</span></p>
</li>
</ul>
<b><div align="center"><center><table border="2" cellpadding="2" cellspacing="0"
width="90%" bgcolor="#8CDAFF">
<tr>
</b><td width="100%"><span style="font-size: 9pt">提示:在C++编程中,判断一个位于堆中的对象是否存在的常用方法是判断指向该对象的指针是否为空。这种机制要求程序员将指向该对象的指针初始化为NULL值,在创建对象时将返回的地址赋给该指针,而在删除对象时将该指针置成NULL值。</span></td>
</tr>
</table>
</center></div><p ALIGN="JUSTIFY"><span style="font-size: 9pt">根据上面的分析,我们很容易把Register程序中的登录数据对话框改成非模态对话框。这样做的好处在于如果用户在输入数据时发现编辑视图中有错误的数据,那么不必关闭对话框,就可以在编辑视图中进行修改。</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">请读者按下面几步操作:</span></p>
<blockquote>
<blockquote>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">在登录数据对话框模板的属性对话框的More
Styles页中选择Visible项。</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">在RegisterView.h头文件的CRegisterView类的定义中加入<br>
<b>public:<br>
CRegisterDialog* m_pRegisterDlg;</span></p>
</b><p ALIGN="JUSTIFY"><span style="font-size: 9pt">在RegisterView.h头文件的头部加入对CRegisterDialog类的声明<br>
<b>class CRegisterDialog;<br>
</b>加入该行的原因是在CRegisterView类中有一个CRegisterDialog类型的指针,因此必须保证CRegisterDialog类的声明出现在CRegisterView之前,否则编译时将会出错。解决这个问题有两种办法,一种办法是保证在#include
“RegisterView.h”语句之前有#include “RegisterDialog.h”语句,这种办法造成了一种依赖关系,增加了编译负担,不是很好;另一种办法是在CRegisterView类的声明之前加上一个对CRegisterDialog的声明来暂时“蒙蔽”编译器,这样在有#include
“RegisterView.h”语句的模块中,除非要用到CRegisterDialog类,否则不用加入#include
“RegisterDialog.h”语句。</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">在RegisterDialog.cpp文件的头部的#include语句区的末尾添加下面两行<br>
<b>#include "RegisterDoc.h"<br>
#include "RegisterView.h"</span></p>
</b><p ALIGN="JUSTIFY"><span style="font-size: 9pt">利用ClassWizard为CRegisterDialog类加入OnCancel和PostNcDestroy成员函数。加入的方法是进入ClassWizard后选择Message
Maps页,并在Class name栏中选择CRegisterDialog。然后,在Object IDs栏中选择IDCANCEL后,在Messages栏中双击BN_CLICKED,这就创建了OnCancel。要创建PostNcDestroy,先在Object
IDs栏中选择CRegisterDialog,再在Messages栏中双击PostNcDestroy即可。</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">分别按清单5.10和5.11,对CRegisterView类和CRegisterDialog类进行修改。</span></p>
</blockquote>
</blockquote>
<p><b><span style="font-size: 9pt"> </span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">清单5.10 CRegisterView类的部分代码</span></b></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">CRegisterView::CRegisterView()</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">{</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">// TODO: add construction code here</span></p>
<p><b><span style="font-size: 9pt"> </span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">m_pRegisterDlg=NULL; //指针初始化为NULL</span></b></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">}</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt"> </span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">void CRegisterView::OnEditRegister() </span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">{</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">// TODO: Add your command handler code
here</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt"> </span></p>
<p><b><span style="font-size: 9pt"> </span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">if(m_pRegisterDlg)</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">m_pRegisterDlg->SetActiveWindow(); //激活对话框</span></p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -