友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

C语言实例教程(PDF格式)-第22部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


对象由直接的或间接的由类CWnd派生,并且有着它自己的消息映射和 

处理函数。框架使用这个消息映射来将到来的消息映射到它们的处理 

函数。  



对于命令,我们所需做的只是建立命令到它们的处理函数之间的链 

接,通常使用ClassWizard来完成这一步工作,然后编写绝大多数的 

命令处理程序。  



Windows消息通常发送到主框架窗口,但是命令消息将可能传送到其 

它的对象,框架通过一个命令目标对象的标准顺序来传递命令,这些 

命令目标对象至少有一个可能 (并不是一定)包含该命令的处理函数。 

每一个命令目标对象检查它的消息映射以查看是否有一个命令处理函 

数来处理到来的消息。  


…………………………………………………………Page 180……………………………………………………………

不同的命令目标类在不同的时候检查它们 自己的消息映射。典型的, 

一个类将命令传送给其它一些类,这使得这些类具有最先处理该消息 

的机会。如果这些类中没有一个处理了该命令,最初的那个类将检查 

它的消息映射,然后,如果它也没有提供相应的处理函数,它可能会 

将该命令传送给更多的命令目标。表4。2描述了构成这一顺序的结 

构。通常的顺序是先传送给当前激活子命令目标对象,再传送给自 

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



                    表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派 

生的类都可以提供了一个消息映射来处理消息,这时我们需要在类声 

明中使用宏DECLARE_MESSAGE_MAP,然后在定义该类的成员函数 

的。CPP文件中使用宏BEGIN_MESSAGE_MAP,然后为每一个消息处理函 

数添加宏入口,最后使用宏END_MESSAGE_MAP。  



  l 注意:  



  l 如果你在DECLARE_MESSAGE_MAP之后声明了任何成员,必须为它们 

   重新指定新的访问类型(public、private或protected)。为了避 

   免出现错误,我们一般都在类声明的最底部使用宏 

   DECLARE_MESSAGE_MAP。  


…………………………………………………………Page 185……………………………………………………………

                              第四节 对话框类  



本节讲述应用程序DialogDemo的对话框类CDialogDemoDlg。由于 

DialogDemo是一个基于对话框的应用程序,因此该对话框也将是应用 

程序的主窗口。  



下面我们先给出头文件DialogDemoDlg。h的清单:  



// DialogDemoDlg。h : 头文件  



//  



#if !defined 

(AFX_DIALOGDEMODLG_H__7ABABF8A_0C8C_11D2_BC21_0000B4810A31__INCLUDED_)  



#define AFX_DIALOGDEMODLG_H__7ABABF8A_0C8C_11D2_BC21_0000B4810A31__INCLUDED_  



#if _MSC_VER 》= 1000  



#pragma once  



#endif // _MSC_VER 》= 1000  



/////////////////////////////////////////////////////////////////////////////  



// CDialogDemoDlg 对话框  



class CDialogDemoDlg : public CDialog  



{  



// 构造  



public:  



CDialogDemoDlg(CWnd* pParent = NULL); // 标准构造函数  



// Dialog Data  



//{{AFX_DATA(CDialogDemoDlg)  



enum { IDD = IDD_DIALOGDEMO_DIALOG };  



// 注意:ClassWizard 将在此添加数据成员  



//}}AFX_DATA  



// 由 ClassWizard 生成的虚函数重载  



//{{AFX_VIRTUAL(CDialogDemoDlg)  


…………………………………………………………Page 186……………………………………………………………

protected:  



virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持  



//}}AFX_VIRTUAL  



// 实现  



protected:  



HICON m_hIcon;  



// 生成的消息映射函数  



//{{AFX_MSG(CDialogDemoDlg)  



virtual BOOL OnInitDialog();  



afx_msg void OnSysmand(UINT nID; LPARAM lParam);  



afx_msg void OnPaint();  



afx_msg HCURSOR OnQuery
返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!