友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
喜书网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

C语言实例教程(PDF格式)-第30章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




身,最后传送给其它的命令目标。  



                    表4。 2 标准命令传送路径  



              该类型的对象获     它将按下面的顺序给自 

              取某一命令       身和其它命令目标对象 

              时……         处理该命令的机会  



              MDI框架窗口     1。       当前激活 

               (CMDIFrameWnd)   CMDIChildWnd  

                          2。 当前框架窗口自身  

                          3。  应用程序 (CWinApp对 

                          象)  



              文档框架窗口      1。 当前激活视  

               (CframeWnd, 2。 当前框架窗口  

              CMDIChildWnd)  3。  应用程序 (CWinApp对 

                          象)  



              视           1。 当前视  

                          2。 与视相关联的文档  



              文档          1。 当前文档  

                          2。  与文档相关联的文档 

                          模板  



              对话框         1。 当前对话框  

                          2。  拥有当前对话框的窗 

                          口  

                          3。  应用程序 (CWinApp对 

                          象)  



上面的过程看起来很复杂,并且添加了程序的开销,但是相比处理程 

序对命令的响应来说,传送命令的开销要小得多,因为仅当用户与一 

个用户界面对象进行交互时框架才生成相应的命令。  



当使用AppWizard创建新的框架应用程序 (skeleton            application) 

时,AppWizard就已经为它所创建的每一个命令目标类编写了相应的 

消息映射。在这些消息映射中,有一些已经添加了对某些消息和预定 

义命令的处理,而其它一些只是为了下一步添加处理函数的占位符。  


…………………………………………………………Page 181……………………………………………………………

类的消息映射位于该类的。CPP文件中,我们通常使用ClassWizard为 

每一个类将要处理的消息和命令添加入口。一个典型的消息映射具有 

如下的结构,它来自文件DialogDemo。cpp :  



BEGIN_MESSAGE_MAP(CDialogDemoApp; CWinApp)  



//{{AFX_MSG_MAP(CDialogDemoApp)  



// 注意 ClassWizard 将在此添加或删除映射宏。  



// 不要删除你在这里看到的这些生成代码块 !  



//}}AFX_MSG  



ON_MAND(ID_HELP; CWinApp::OnHelp)  



END_MESSAGE_MAP()  



上面的消息映射包括一系列的宏。消息映射位于两个宏—— 

BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间,其它的宏,如 

ON_MAND构成了消息映射的内容。  



  l 注意:  



  l 在消息映射宏的后面没有分号。  



消息映射还包括了下面形式的注释:  



//{{AFX_MSG_MAP(CDialogDemoApp)  



//}}AFX_MSG_MAP  



在两行注释之间包括了消息映射入口,但不要求所有的消息映射入口 

都在这两行注释之间。当使用ClassWizard编写入口时,它将使用这 

些特殊的注释。所有由ClassWizard生成的注释都位于这两行注释之 

间。  



  l 注意:  



  l 除非你确实不想在程序中再使用ClassWizard,不要更改// 

    {{AFX_MSG_MAP和//}}AFX_MSG_MAP记号,这是ClassWizard进行程 

    序相关数据库管理的特殊标记。  



当使用ClassWizard创建新类时,相应的消息映射将由ClassWizard 自 

动生成。而且,在前面的示例代码中,我们还看到了不要随意修改由 

ClassWizard生成的消息映射项的警告。但是,对于那些有经验的程 


…………………………………………………………Page 182……………………………………………………………

序员,使用源代码编辑器来手动的创建消息映射也是完全可行的。  



我们注意到前面的BEGIN_MESSAGE_MAP具有下面的格式,它具有两个 

参数:CDialogDemoApp和CWinApp。  



BEGIN_MESSAGE_MAP(CDialogDemoApp; CWinApp)  



第一个参数CDialogDemoApp表示消息映射所属的类,第二个参数 

CWinApp表示CDialogDemoApp的直接基类,这向我们暗示了一点,这 

就是说,如果框架在类CDialogDemoApp中没有找到某一特定消息或命 

令的映射入口,它将按照类的继承结构依次查找该与该消息或命令相 

匹配的入口。如果按照这种方式还是未能找到一个匹配的映射项,对 

于命令,框架将将它传送给下一个命令目标,对于标准Windows消 

息,框架将将它传递给一个合适的默认窗口过程。为了加速消息映射 

匹配的速度,框架使用了一种类似于磁盘缓存的机制,它保存了与最 

近匹配项有关的信息,以便在获取相同的消息时可以很快的找到与消 

息相匹配的消息映射。事实上,消息映射同使用虚函数相比,在某些 

方面要更为有效。  



下面我们讨论一下消息处理函数的声明。消息处理函数的声明需要遵 

从一些规则与协议,这些规则和协议因消息所属的种类不同而有所不 

同。  



在类CWnd中定义了标准的Windows消息处理函数,这些消息以前缀WM_ 

开头。相应的消息处理函数的命名基于消息的名称。举例来说,消息 

WM_PAINT的处理函数在CWnd中被声明为  



afx_msg void OnPaint();  



关键字afx_msg使得上面的函数看起来和其它的CWnd成员函数有所不 

同,然而实际上,经过预处理之后,afx_msg将被空白所代替,也就 

是说,除了可以使程序员很清楚的的知道哪一些函数是消息处理函 

数,而哪一些是一般的成员函数。(实际上,该关键字为Microsoft 

公司为今后所作的保留字。)消息处理函数只通过消息映射来实现, 

而消息映射仅依赖于几个标准的预处理宏。  



如果需要重载在基类中定义的消息处理函数,只需简单的使用 

ClassWizard在派生类中定义一个具有相同原型的函数,并且为它添 

加消息映射入口。关于如果使用ClassWizard重载消息处理函数的示 

例我们将会在本书后面的内容中遇到,这里就不再赘述。  



在一些情况下,重载以后的处理函数应该在适当的地方调用基类的被 


…………………………………………………………Page 183……………………………………………………………

重载函数以使得基类和Windows可以处理这些消息。而在什么地方调 

用基类的被重载函数依环境而定。有时候我们需要根据一些条件来决 

定是否需要调用基类的被重载函数,而在另外的一些场合可能恰恰相 

反,我们需要基类的处理函数的返回值来决定是否或如何执行自己的 

处理函数代码。  



  l 注意:  



  l 有些时候我们可能会想到在将传递给消息处理函数的参数再传递 

   给基类的处理函数时修改它们。比如说,我们有可能想到通过修 

   改OnChar处理函数的nChar参数来在用户输入时屏蔽掉一些字符。 

   但是这样做是不安全的,如果一定需要这样做,我们应该使用类 

   CWnd的成员函数SendMessage,而不是直接修改传递给消息处理函 

   数的参数。  



按照惯例,我们在消息处理函数名的前面都使用了前缀 “On”。并且 

消息处理函数可能带有几个参数,也可能一个参数也没有。一些消息 

处理函数可以返回值,而另一些可能被声明为void。可以在Class  

Library  Reference中找到以WM_开头的消息的默认处理函数,它们都 

是类CWnd的成员函数,并且具有前缀 “On”。这些成员函数在类CWnd 

中的声明均带有前缀afx_msg。  



对于命令或控件通知消息,MFC并未提供默认的处理函数。因此,我 

们需要根据命名约定来自己命名或编写这些消息处理函数。当将命令 

或控件通知映射到处理函数时,ClassWizard根据命令ID或控件通知 

代码建议处理函数名。  



举个例子来说,按照命名约定,响应File菜单下的Open命令的消息处 

理函数将被命名为  



afx_msg void OnFileOpen();  



对于一些很常见的用户界面元素,在框架中已为它们预定义了一些命 

令ID,比如与File菜单下的Open命令对应的命令ID为ID_FILE_OPEN, 

这些预定义ID可以在文件AFXRES。H 中找到。下面是所支持的最重要的 

一些命令的列表:  



  l File菜单命令:New、Open、Close、Save、Save As、Page  

   Setup、Print Setup、Print、Print Preview、Exit以及最近使 

   用的文件  



  l Edit菜单命令:Clear、Clear All、Copy、Cut、Find、Paste、 


…………………………………………………………Page 184……………………………………………………………

   Repeat、Replace、Select All、Undo以及 Redo。  



  l View菜单命令:Toolbar以及Status Bar。  



  l Window菜单命令:New、Arrange、Cascade、Tile Horizontal、 

   Tile Vertical以及Split。  



  l Help菜单命令:Index、Using Help以及About。  



  l OLE命令 (位于Edit菜单):Insert New Object、Edit Links、 

   Paste Link、Paste Special以及typename Object (谓词命令)。  



再举一个例子,按照命名约定的建议,对一个标签为Default的按钮 

控件的BN_CLICKED通知消息处理函数将被命名为:  



afx_msg void OnClickedDefault();  



这样,我们就可以将IDC_DEFAULT的ID与一个命令相关联,这样该命 

令等价于应用程序指定的用户界面对象。  



以上讲到的两类消息 (命令和控件通知消息)的处理函数都不带任何参 

数,同时也不返回任何值。  



在上面的例子中,每一个处理函数都对应了单个命令ID或控件ID。然 

而,在MFC的消息映射机制中,我们还可能将单个处理函数对应一个 

命令ID或控件ID范围,但是,ClassWizard不支持命令ID或控件ID范 

围的处理函数的映射,因此我们必须手动的添加消息映射入口。由于 

到目前为止所讲述的内容还不足以提供了一个完整的示例,因此我们 

将在本书后面的内容中给出以上内容的示例程序。  



在本节的最后解释一下宏DECLARE_MESSAGE_MAP。该宏一般出现的支 

持消息映射的类定义的尾部。前面已经说过,每一个从CCmdTarget派 

生的类都可以提供了一个消息映射来处理消息,这时我们需要在类声 
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!