消息映射是将消息处理函数与它要处理的特定消息链接起来的一种机制。消息映射是应用 MFC 方法进行 Windows 编程的主要组成部分。
Windows 消息主要有 3 种类型,即标准Windows 消息、控件消息和命令消息。
1.标准Windows 消息
出 WM_COMMAND 以外,所有以“WM_”(Windows Massage)为前缀的消息都是标准 Windows 消息。标准的 Windows 消息由窗口类或视图类处理。标准 Windows 消息都有默认的处理函数,这些函数在 CWnd 类中进行了预定义。MFC 类库以消息名为基础形成这些处理函数的名称,这些函数的名称都以前缀“On”开始。有的处理函数不带参数,有的带几个参数。这些消息处理函数的说明一般都有“afx_msg”的前缀,用于把处理函数与其他的窗口成员函数区分开来,这些函数都是通过消息映射实现的。例如,消息 WM_CHAR 的处理函数在 CWnd 中声明为
在afxwin.h中afx_msg的解释:
#ifndef afx_msg
#define afx_msg // intentional placeholder
#endif
afx_msg只是定义了这个符号而已。这个对编译器来说,相当于什么都没有,对于程序员来说,我们可以看到这样的符号。对于类向导来说,这个符号才是有意义的,它是一个消息处理函数的前缀。类向导生成的消息函数,分发函数,事件响应函数都以这个为前缀,如果去掉了,向导将不能识别。
标准的 Windows 消息又分为 3 类:键盘消息、鼠标消息和窗口消息。
(1)键盘消息
键盘消息与键盘某个键的动作相关联。常见的键盘消息有以下几种。
所有键盘消息处理函数的原型都很相似。以 WM_CHAR 消息处理函数 OnChar()为例来说明。此函数的原型为
其中,参数 nChar是所按键的字符代码值;nRepCnt 表示用户重复击键的次数;nFlags表示扫描码、先前键状态和键转换状态等,其具体含义如表所示
nFlags取值 | 含义 |
---|---|
0~7 | 表示扫描码 |
8 | 若同时按下扩展键,则置位;否则清位 |
9,10 | 不使用 |
11,12 | 有 Windows 内部使用 |
13 | 若同时按下 Alt 键,则置位;否则清位 |
14 | 指明先前键状态。如果消息发出前键是按下的,则置位;否则清位 |
15 | 指明键转换状态。如果按键已松开,则置位;否则清位 |
(2)鼠标消息
鼠标消息设计鼠标的单击、双击、拖动。常用的鼠标消息有以下几种:
所有鼠标操作的处理函数都有很相似的原型,他们都有两个参数。以处理鼠标左键按下消息的函数 OnLButtonDown()为例。此函数的原型为:
其中,参数 point 是鼠标事件发生时鼠标所在的位置。它是相对于窗口左上角的水平 X 坐标和垂直 Y 坐标而言的。参数nFlags 指明鼠标按键的状态以及鼠标事件发生时键盘上某些键的状态,每一状态都可以用nFlags 的一位表示,具体函数见表
nFlags取值 | 含义 | nFlags取值 | 含义 |
---|---|---|---|
MK_CONTROL | Ctrl 键按下 | MK_RBUTTON | 右键按下 |
MK_LBUTTON | 左键按下 | MK_SHIFT | shift 键按下 |
MK_MBUTTON | 中间键按下 |
(3)窗口消息
窗口消息一般与创建窗口、绘制窗口、移动窗口和销毁窗口等动作有关。在 MFC 应用程序汇总,窗口消息是由视图类、窗口类及它们的派生类处理的。常见的窗口消息如下:
WM_PAINT:当客户区产生移动或者显示事件、当用户窗口产生改变大小事件、当产生下拉菜单关闭并需要恢复被覆盖部分事件、当产生 Windows 清除对话框或者消息框并需要恢复被覆盖部分事件时,会产生 WM_PAINT 消息。它的消息处理函数原型为:
WM_TIMER:每当定时器被触发时,系统就发送 WM_TIMER 消息。它的消息处理函数原型为
其中,参数nIDEvent是计时器的标识符。
这里还有博主写的对话框的常用回调函数(窗口创建时的消息和窗口销毁时的消息) https://blog.csdn.net/qq_41291253/article/details/89203975
2.控件消息
控件消息是指控件或其他子窗口向父窗口发送 WM_COMMAND 消息。发送控件消息的控件使用唯一的 ID 来识别,使用控件类来操控。从控件传给系统的消息,它的前缀的最后一个字符为 N;由系统发送给控件的消息,其前缀的最后一个字符为M。
例如,当用户对编辑框中的文本进行修改时,编辑框将发送给父窗口一条包含控件通知码 EN_CHANGE 的 WM_COMMAND 消息。与其他标准 Windows 消息一样,控件消息也应该在视图类、窗口类中进行处理。但是,如果用户单击按钮控件时,发出的控件通知消息 BN_CLICKED 将作为命令消息来处理。
3.命令消息
命令消息是由菜单项、工具栏按钮、快捷键等用户界面对象发出的 WM_COMMAND 消息。命令消息与其他消息不同,他可被更广泛的对象如文档、文档模板、应用程序对象、窗口和视图处理。
MFC 采用消息映射来处理消息。这种消息映射机制包括一组消息映射宏,用于把一个 Windows 消息和其消息处理函数联系起来。MFC 应用程序框架提供了消息映射功能,所有从 CCmdTarget 类派生出来的类都能够拥有自己的消息映射。
与 MFC 消息映射机制有关的宏有以下 3 个:DECLARE_MESSAGE_MAP()宏、BEGIN_MESSAGE_MAP(MyClass, MybaseClass)宏和 END_MESSAGE_MAP()宏。
为了使用消息映射宏,首先在类定义的结尾用 DECLEAR_MESSAGE_MAP()宏来声明使用消息映射,该宏表示在为各个处理函数所写的类声明之后存在消息映射条目,这些函数是该类的成员函数。然后在类的实现源文件中用BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()宏来定义消息映射。MFC 应用程序 MESSAGE_MAP 消息映射的形式如下。
BEGIN_MESSAGE_MAP(MyClass, MybaseClass)
//{{AFX_MSG_MAP(MyClass) //类向导维护消息映射宏的标记
ON_... //MFC 预定义消息映射宏
ON_MESSAGE(message, memberFun) //用户自定义消息映射宏
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
其中,MyClass 是拥有消息映射的派生类名,MyBaseClass 是其基类名。对于不同类型的消息,消息映射宏的格式及参数是不同的,见下表。
消息类型 | 宏格式 | 参数 |
---|---|---|
标准 Windows 消息 | ON_WM_XXX | 无 |
命令消息 | ON_COMMAND | 命令消息 ID,消息处理函数名 |
用户界面更新命令消息 | ON_UPDATE_COMMAND_UI | 命令消息 ID,消息处理函数名 |
空间通知消息 | ON_CONTROL | 控件消息 ID,消息处理函数名 |
用户自定义消息 | ON_MESSAGE | 自定义消息 ID,消息处理函数名 |
已注册用户自定义消息 | ON_REGISTERED_MESSAGE | 自定义消息 ID,消息处理函数名 |
命令 ID 范围 | ON_COMMAND_RANGE | 连续范围内命令 ID 的开始和结束 |
更新命令 ID 范围 | ON_UPDATE_COMMAND_UI_RANGE | 连续范围内命令 ID 的开始和结束 |
空间的 ID 范围 | ON_CONTROL_RANGE | 控件通知码和连续范围内的命令 ID 的开始和结束 |
具体demo 请见博主另一篇文章:MFC 消息映射机制 https://blog.csdn.net/qq_41291253/article/details/103321786
自定义消息步骤如下:
1.定义消息 ID 值
2.声明自定义消息处理函数
3.在消息映射表中添加自定义消息映射宏
4.定义自定义消息的实现代码
5.在需要运行自定义消息的地方发送自定义消息。
具体请看博主的这篇文章 用户自定义消息:https://blog.csdn.net/qq_41291253/article/details/103321802