📄 chap04.html
字号:
<P>CDialogDemoApp::CDialogDemoApp()</P>
<P>{</P>
<P>	// TODO: 在这里添加构造代码,</P>
<P>	// 将所有重要的初始化放入 InitInstance</P>
<P>}</P>
<P>/////////////////////////////////////////////////////////////////////////////</P>
<P>// 唯一的 CDialogDemoApp 对象</P>
<P>CDialogDemoApp theApp;</P>
<P>/////////////////////////////////////////////////////////////////////////////</P>
<P>// CDialogDemoApp 初始化</P>
<P>BOOL CDialogDemoApp::InitInstance()</P>
<P>{</P>
<P>	AfxEnableControlContainer();</P>
<P>	// 标准初始化</P>
<P>	// 如果你不需要使用这些特性,并且希望减小最终可执行文件的大小,你可以删除</P>
<P>	// 下面的特定的初始化过程中不需要的部分。</P>
<P>#ifdef _AFXDLL</P>
<P>	Enable3dControls();			// 当通过共享 DLL 使用 MFC 时调用</P>
<P>#else</P>
<P>	Enable3dControlsStatic();	// 当通过静态链接到 MFC 时调用</P>
<P>#endif</P>
<P>	CDialogDemoDlg dlg;</P>
<P>	m_pMainWnd = &dlg;</P>
<P>	int nResponse = dlg.DoModal();</P>
<P>	if (nResponse == IDOK)</P>
<P>	{</P>
<P>		// TODO: 在这里添加当使用 OK 关闭对话框时的处理代码</P>
<P>	}</P>
<P>	else if (nResponse == IDCANCEL)</P>
<P>	{</P>
<P>		// TODO: 在这里添加当使用 Cancel 关闭对话框时的处理代码</P>
<P>	}</P>
<P>	// 由于对话框已被关闭,返回 FALSE 并退出应用程序,而不需要启动应用程序</P>
<P> // 消息泵。</P>
<P>	return FALSE;</P>
<P>}</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">上面的源代码为类</FONT><FONT SIZE=3>CDialogDemoApp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>提供了一个空的构造函数和一个对</FONT><FONT SIZE=3>InitInstance</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的默认重载。我们把讨论的重点放在</FONT><FONT SIZE=3>InitInstance</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>成员函数上。在</FONT><FONT SIZE=3>InitInstance</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>成员函数的一开始,先调用</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>全局函数</FONT><FONT SIZE=3>AfxEnableControlContainer</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,该函数为应用程序提供了对</FONT><FONT SIZE=3>OLE</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>控件</FONT><FONT SIZE=3>(</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>新的术语称作</FONT><FONT SIZE=3>ActiveX</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>控件</FONT><FONT SIZE=3>)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的支持。</P>
<P ALIGN="JUSTIFY">接着,</FONT><FONT SIZE=3>InitInstance</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>成员函数调用类</FONT><FONT SIZE=3>CWinApp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的成员函数</FONT><FONT SIZE=3>Enable3dControls</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或</FONT><FONT SIZE=3>Enable3dControlsStatic</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>以允许对话框和窗口可以使用具有三维外观的控件。这两个成员函数加载</FONT><FONT SIZE=3>CTL3D32.DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>并且注册应用程序。</FONT><FONT SIZE=3>Enable3dControls</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>Enable3dControlsStatic</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的区别在于一个在链接到</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>动态链接库时使用,而另一个在使用</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的静态链接时使用。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>自动为以下窗口类提供</FONT><FONT SIZE=3>3D</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>控件效果:</P>
<UL>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY"><LI>CDialog</LI></P>
<P ALIGN="JUSTIFY"><LI>CDialogBar</LI></P>
<P ALIGN="JUSTIFY"><LI>CFormView</LI></P>
<P ALIGN="JUSTIFY"><LI>CPropertyPage</LI></P>
<P ALIGN="JUSTIFY"><LI>CPropertySheet</LI></P>
<P ALIGN="JUSTIFY"><LI>CControlBar</LI></P>
<P ALIGN="JUSTIFY"><LI>CToolBar</LI></P></UL>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">如果你所希望得到</FONT><FONT SIZE=3>3D</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>效果的控件属于以上类型之一的话,你只需调用</FONT><FONT SIZE=3>Enable3dControls</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或</FONT><FONT SIZE=3>Enable3dControlsStatic</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>即可。反之则必须直接调用相应的</FONT><FONT SIZE=3>CTL3D32 API</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数。</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">然后在</FONT><FONT SIZE=3>InitInstance</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中定义了类型为</FONT><FONT SIZE=3>CDialogDemoDlg</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的对象</FONT><FONT SIZE=3>dlg</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,然后将其指针赋予类型为</FONT><FONT SIZE=3>CWnd</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的成员变量</FONT><FONT SIZE=3>m_pMainWnd</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。成员变量</FONT><FONT SIZE=3>m_pMainWnd</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>用来保存指向线程主窗口对象的指针,当由</FONT><FONT SIZE=3>m_pMainWnd</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>引用的窗口被关闭时,该线程由</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>自动终止。当应用程序的主线程被终止时,该应用程序相应的也被终止。如果该成员的值为</FONT><FONT SIZE=3>NULL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,则应用程序的</FONT><FONT SIZE=3>CWinApp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>对象的主窗口被用来判断线程何时终止。成员</FONT><FONT SIZE=3>m_pMainWnd</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>具有共有访问权限。对于工作者线程而言,该数据成员的值从其父线程继承。</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">接着</FONT><FONT SIZE=3>InitInstance</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>调用了对象</FONT><FONT SIZE=3>dlg</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的成员函数</FONT><FONT SIZE=3>DoModal</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,该成员函数以模态方式调用对话框并在结束时返回对话框的结果。在对话框激活时,该成员函数处理所有与用户的交互,也就是说,对于模态对话框,用户不可以在对话框关闭之前与其它窗口进行交互。</P>
<P ALIGN="JUSTIFY">如果用户单击了对话框中的</FONT><FONT SIZE=3>OK</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或</FONT><FONT SIZE=3>Cancel</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>按钮,相应的消息处理函数,如</FONT><FONT SIZE=3>OnOK</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或</FONT><FONT SIZE=3>OnCancel</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>被调用以试图关闭对话框。</FONT><FONT SIZE=3>OnOK</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>成员函数的默认行为为验证和更新对话框数据并以结果</FONT><FONT SIZE=3>IDOK</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>关闭对话框,</FONT><FONT SIZE=3>OnCancel</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的默认行为为以结果</FONT><FONT SIZE=3>IDCANCEL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>关闭对话框并不更机关报所有对话框数据。通过重载这些消息处理函数可以改变它们的行为。</P>
<P ALIGN="JUSTIFY">在</FONT><FONT SIZE=3>DoModal</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>返回时,对话框将被关闭,理所当然的,基于该对话框的应用程序也应该被关闭,因此在</FONT><FONT SIZE=3>InitInstance</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的最后使用了语句</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>return FALSE;</P>
</FONT><FONT FACE="仿宋_GB2312" LANG="ZH-CN" SIZE=4><P ALIGN="CENTER"><A NAME="_Toc425696870">第三节</FONT><FONT SIZE=4> MFC</FONT><FONT FACE="仿宋_GB2312" LANG="ZH-CN" SIZE=4>应用程序的消息循环</A></P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">上面的对应用程序的类的定义和声明还包括了</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的消息循环</FONT><FONT SIZE=3>(message loop)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,下面我们来详细的描述</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>应用程序的消息循环。框架应用程序处理</FONT><FONT SIZE=3>Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>消息的方式同其它</FONT><FONT SIZE=3>Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>应用程序是类似的,只不过它提供了一些方法来使得这个过程更加的方便,更加的易于维护和更好的包装。</P>
<UL>
</FONT><FONT FACE="黑体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>注意:</LI></P>
</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>为便于读者理解,在此我们给出一个</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>对对话框控制的支持的树图</FONT><FONT SIZE=3>(</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>如图</FONT><FONT SIZE=3>4.8</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>所示</FONT><FONT SIZE=3>)</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>。</LI></P></UL>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">在类</FONT><FONT SIZE=3>CWinApp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的</FONT><FONT SIZE=3>Run</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>成员函数中的消息循环获取各种事件所产生的排队消息</FONT><FONT SIZE=3>(queued message)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,应用程序消息循环的框架实现是将它们分发到合适的窗口。</P>
<P ALIGN="JUSTIFY">在</FONT><FONT SIZE=3>MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中,每一个单独的消息都由一个专门的函数进行处理,这种称作消息处理函数</FONT><FONT SIZE=3>(message-handler function</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或</FONT><FONT SIZE=3>message handler</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或</FONT><FONT SIZE=3>handler)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的专门函数以类的成员函数的方式进行定义。处理命令消息的函数还常被称作命令处理函数</FONT><FONT SIZE=3>(command handler)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>应用程序是消息驱动的,因此编写消息处理函数就成了编写框架应用程序的工作中的一个很大的组成部分。</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="CENTER"><IMG SRC="Image238.gif" tppabs="http://166.111.167.223/computer/cai/visual_c++_5.0_programming/Image238.gif" WIDTH=163 HEIGHT=318></P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="CENTER">图</FONT><FONT SIZE=1>4. 8 MFC</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1>中对话框控件类的树状结构图</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">每一个有能力获取消息或命令的框架类都有它自己的消息映射</FONT><FONT SIZE=3>(message map)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,框架使用消息映射来建立消息和命令到它们的处理函数之间的链接。所有从类</FONT><FONT SIZE=3>CCmdTarget</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>派生的类都可以有它自己的消息映射。尽管我们常常区别消息和命令两个术语,但这里所说的消息映射同时对它们进行处理。</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">下面我们来看一下消息是如何发送和获取的。</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">很多消息来自于用户和程序之间的交互:当用户使用鼠标单击了菜单项或工具条按钮或按下了快捷键时,即产生了命令。同样由用户产生的</FONT><FONT SIZE=3>Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>消息还可以来自移动窗口或改变窗口的大小。此外,当程序启动或终止、窗口获得或失去焦点等等事件发生时,相应的</FONT><FONT SIZE=3>Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>消息也将被发送。控件作为一种特殊形式的窗口,相应的控件通知消息也在类似的情形下产生。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">Run</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>成员函数用来获取消息并将它们发送到合适的窗口,很多的命令消息被发送到应用程序的主窗口,由类库预先定义的</FONT><FONT SIZE=3>WindowProc</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>函数获得这些消息,然后根据所获得的消息的类型来以不同的方式对它们进行处理。</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">最初接受消息的必须是一个窗口对象。</FONT><FONT SIZE=3>Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>消息通常直接由该窗口对象进行处理。而命令消息一般由应用程序的主框架窗口开始,按照命令路径描述的命令目标链进行处理。</P>
<P ALIGN="JUSTIFY">当一个命令目标链获得消息或命令时,它将搜索它的消息映射以寻找匹配项。如果该消息的一个处理函数存在,该处理函数将被调用。</P>
<P ALIGN="JUSTIFY">与命令不同,对于标准</FONT><FONT SIZE=3>Windows</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>消息,它们并不经过命令目标链,通常由该消息的目标窗口进行处理,这个目标窗口可能是主框架窗口,也可能是一个</FONT><FONT SIZE=3>MDI</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>子窗口
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -