引言: 众所周知,windows是基于消息驱动的,作好消息处理是WINDOWS编程的要害任务之一,用VC制作WINDOWS程式同样离不开消息的处理。虽然VC 6的类向导可以完成绝大部分工作,但不幸的是,它并不能完成所有的工作。这就要求我们对 VC中消息的处理有一个比较清淅的熟悉。只有这样才可能在必要的时候亲自动手完成一些复杂的消息映射处理。
在MFC中消息是通过一种所谓的消息映射机制来处理的。其实质是一张消息及其处理函数的一一对应表以及分析处理这张表的应用框架内部的一些程序代码.这样的好处是可以避免像早期的SDK编程一样需要罗列一大堆的CASE语句来处理各种消息.由于不同种类的消息其处理方法是不同的,所以我们有必要先弄清楚 WINDOWS消息的种类。
背景: WINDOWS 消息的种类
WINDOWS中消息主要有以下三种类型:
1、标准的WINDOWS消息:这类消息是以WM_为前缀,不过WM_COMMAND例外。 例如: WM_MOVE、WM_QUIT等.
2、命令消息:命令消息以WM_COMMAND为消息名.在消息中含有命令的标志符ID,以区分具体的命令.由菜单,工具栏等命令接口对象产生.
复制于hot007.com 3、控件通知消息:控件通知消息也是以WM_COMMAND为消息名.由编辑框,列表框,子窗口发送给父窗口的通知消息.在消息中包含控件通知码.以区分具体控件的通知消息.
其中标准的WINDOWS消息及控件通知消息主要由窗口类即直接或间接由CWND类派生类处理.相对标准WINDOWS消息及控件通知消息而言,命令消息的处理对象范围就广得多.它不仅可以由窗口类处理,还可以由文档类,文档模板类及应用类所处理。
方法: 不同种类消息的映射方法。
在以上三种消息中,标准的WINDOWS消息映射是相当简单的。可直接通过类向导完成不同消息的映射处理,所以不在本文讨论之列。
凡是从CcmdTarget类派生的类都可以有消息映射.消息映射包括如下两方面的内容:
在类的定义文件中(.H)中加上一条宏调用:
DECLARE_MESSAGE_MAP()
通常这条语句中类定义的最后.
在类的实现文件(.CPP)中加上消息映射表:
BEGIN_MESSAGE_MAP(类名,父类名)
………..
消息映射入口项.
……….
007网络教程网 END_MESSAGE_MAP( )
幸运的是除了某些类(如没有基类的类或直接从CobjectO类派生的类)外.其它许多类均可由类向导生成.尽管生成的类只是一个框架,需要我们补充内容.但消息映射表已经为我们加好了.只是入口项有待我们加入.
命令消息映射入口项是一个ON_COMMAND的宏.比如文件菜单下的"打开…"菜单(ID值为ID_FILE_OPEN)对应的消息映射入口项为:
ON_COMMAND(ID_FILE_NEW,OnFileOpen)
加入消息映射入口项之后需要完成消息处理函数.在类中消息处理函数都是类的成员函数,要响应一个消息,就必须定义一个该消息的处理函数.定义一个消息处理函数包括以下三方面的内容.
1.在类定义中加入消息处理函数的函数原型(函数声明)
2.在类的消息映射表中加入相应的消息映射入口项.
3.在类的实现中加入消息处理函数的函数体.
需要说明的是消息处理函数的原型一定要以afx_msg打头.比如:
afx_msg OnFileOpen();// 函数原型
作为约定.消息处理函数一般以On打头
但有时我们可能想用一个消息处理函数来处理一批消息。这时类向导就无能为力了。我们必须手工加入消息映射来完成这种工作。可用如下方法实现:
jc567.cn 首先在处理该消息所在类的实现文件(亦即.CPP)中加入的消息映射入口:
...
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
file://{{AFX_MSG_MAP(CMyApp)
...
file://}}AFX_MSG_MAP
ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, OnDoSomething)
END_MESSAGE_MAP( )
...
粗体标志的语句是我们加入的语句(以后约定我们加入的语句均用粗体标志).其中我们使用了宏ON_COMMAND_RANGE来实现从命令消息ID_MYCMD_ONE到 ID_MYCMD_TEN都由OnDoSomthing一个消息函数处理.注重.ID_MYCMD_ONE到 ID_MYCMD_TEN的ID值一定要连续.且ID_MYCMD_ONE值一般较小.
完成上述工作之后我们还需要在该类的头文件(亦即.H)中加入消息处理函数的申明:
// Generated message-map functions
protected:
file://{{AFX_MSG(CMyApp)
...
file://}}AFX_MSG
afx_msg void OnDoSomething( UINT nID );
DECLARE_MESSAGE_MAP()
由于这不是VC类向导加入的函数申明,所以放在了//}}AFX_MSG之外.
007网络教程网 注重这个消息处理函数有一个UINT类型参数.而处理单一命令的消息处理函数一般是没有参数(除更新用户接口对象状态命令消息处理函数).这个参数的主要作用是提供用户选择的命令的ID值.
最后要做的工作就是在该类的实现文件中实现该消息处理函数. 同样,有时我们也想使用一个消息处理函数处理一批更新用户接口对象状态命令消息.方法同上:
首先在.CPP文件中加入语句如下:
...
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
file://{{AFX_MSG_MAP(CMyApp)
...
file://}}AFX_MSG_MAP
ON_UPDATE_COMMAND_UI_RANGE (ID_MYCMD_ONE, ID_MYCMD_TEN, OnUpdateSomething)
END_MESSAGE_MAP( )
...
在该类的头文件(亦即.H)中加入消息处理函数的申明:
// Generated message-map functions
protected:
file://{{AFX_MSG(CMyApp)
...
file://}}AFX_MSG
afx_msg void OnUpdateSomething( CcmdUI * pcmdui );
复制于hot007.com
DECLARE_MESSAGE_MAP()
请各位注重了,仔细的读者已经注重到这里的消息处理函数并未像命令消息处理函数需要一个额外的UINT类型的参数.原因在于pcmdui中已包含了此信息.所以不再需要这个参数了.最后不要忘了完成函数体!
共2页: 上一页 1 [2] 下一页