我觉得消息映射机制关键是几个宏的理解和熟悉。
对于SDK中的switch..case的消息机制我就不多做介绍。然后MFC为了使这个消息机制更加的有模块化,更加的体现封装的特性(哪个类的消息封装到哪个类中),采用了MFC的消息映射机制,与SDK的映射本质上是一样的,都是一一对应的关系(一个消息对应一个消息响应函数)。
在总结这几个宏之前我先说一下消息的总类。因为不同的消息会对应不同的宏:
一:标准消息。标准消息很好理解和记。标准消息就是当你用向导为你的程序添加的消息。
这里的所有消息都是标准消息。
二:命令消息:命令消息也很好理解和记。命令消息就是控件向主窗口传递的消息。向按钮控件的双击消息 ,菜单消息,工具条消息。
三:通告消息。通告消息其实也就是命令消息的一种。之所以单独分出来,就自然有它的特别之处,它的特别只用从它的消息名字个格式和其他命令消息的格式的不同上就可以看出来。通告消息就是你控件在某种情况下产生的消息。这种某种情况描述的很模糊,是因为我不知道怎么具体的通称 。你可以看一下MFC类库详解。里面对于控件的每一个类的说明中都有关于这些消息的说明。
这是CCombox类的声明。其他类一样有 。
四:自定义消息。我不知道书上为什么没有把这个消息类型包含进来。WM_USER+消息。
好了 ,说完了消息类型,我们就来说这么几个宏了。
一:消息注释宏 。
当我们新建一个基于对话框的程序时,我们来打开它的对话框类的头文件。我指的不是关于对话框,所以不要钻牛角尖。在关于消息的那些代码中我们看到:
这里我加入了一下消息,当然这里并不重要。这AFX_MSG的注释部分就是消息注释宏了。
消息注释宏有什么用呢?要回答这个问题之前我想先给另一个截图:
这是在VS2005上截的图。可以看到这里并没有这个宏。但是程序一样运行。说明这个宏没有什么实际的功能上得作用。对于这个消息的作用我摘抄一下别人的一篇文章,文章并不长:
“注释宏”是类似这样的宏:
//}}AFX_MSG_MAP
VC注释宏是给类向导用的,若要使用类向导添加成员变量和成员函数,则要保留注释宏;否则,必须手动添加。
是用于vc编辑器自动生成代码定位用的如果你把它删了相应的classwizad就不能自动生成代码了 。
你添加消息响应的时候是不是发现源代码里多了些代码?那些代码为什么会在那里出现为什么不在别的文件里出现就是因为那里有注释宏它要将代码生成在相应注释宏之间 。
这个注释是让ClassWizard能够分辨出哪些代码是它生成的,哪些是你自己写的。你自己写的代码要在这个注释之外,这样ClassWizard再修改消息映射的时候就不会管你的代码了。
限于以前的硬件速度,ClassWizard比较傻冒,所以需要这些注释宏来定位。从7.0(Visua Studio 2003)l开始,就不再需要了。新的属性页能够自动分析你的代码,为你添加或者删除代码,而无需什么特殊标记的帮忙。因此注释宏已经是历史产物了。
呵呵 ,只是为了向导的设计的。
二: DECLARE_MESSAGE_MAP()宏:声明消息映射宏。
在讨论这个宏之前呢?我可以回答一下网上对于这个宏的一个问题:为什么当你在声明一个消息响应函数的时候,这个函数的声明 你即可以放在这个宏之前 ,还是放在宏之后 。其实要回答这个问题都不需要了解这个宏的内部机制就可以回答了。为什么呢?你想这个宏是在哪?在头文件中,既然在头文件中 ,那么这个宏肯定是起声明的作用,它并不执行动作,既然不执行动作,放哪不可以呢?为了说明我没有在说谎,你可以把这个宏放心的放在类声明中体内的任何地方:
放在了第一句。运行一样不会有错。
为了更加放心的使用它,我们还是有必要的了解它的内部机制。
这个宏其实就在声明一个结构体,一个来存储消息和消息响应函数名字的一个结构体。我可以写一个这么一个相似类型的结构体。如:struct MSGMAP{
UINT nMessage,LONG(*pfn)(HWND,UINT,WPARAM,LPARM); //这个消息响应函数的名字
}
当然它还有其他的东西。但是知道这么一点就足够了。然后接下来的就是往这个结构体中加入内容。也就是加入以后你要加入的想要响应的消息 。这里的加入就要说到另一个组宏了:BEGIN_MESSAGE_MAP(CTestDlg, CDialog) ND_MESSAGE_MAP()。
三. BEGIN_MESSAGE_MAP ND_MESSAGE_MAP()
这里这组宏应该知道他的作用了吧。就是填充那个结构体 。实现一一对应关系。使消息和消息响应函数来对应上 。不过这段代码放在.cpp中看上去格式和其他的响应函数有点不一样。一开始我还错认为了这个的格式跟全局函数的实现一样。但是再仔细看看,就可以知道不是了。
说完了这个消息映射机制,还有个重要的内容要讲讲,这个内容他们老是不去涉及,但是我却觉得非常的重要,对于我们来说,因为这些内容才是我们必须要手动来添加的。那就是对于这两个宏之间的内容的代码的添加。
一.说到代码的真正添加,我一样在VS2005用向导自动为程序添加一个按钮控件,并添加响应函数。
和上面的图进行比较,可以看到在VS中对于注释代码的加灰它已经不用了。而且可以看到,它不会像VC6.0一样在宏上面来添加OnBnClickedButton1了。而是另起一行。这个原因应该是没有注释宏的关系吧。
但是这个不是最重要的 ,最重要的是在声明消息响应函数的时候他们前面有个奇怪的afx_msg宏。对于这个宏的作用:afx_msg这类的宏没有实质上的意义,只是编译器用来检查特殊用途的 标记而已,你可以无视。所以如果你不相信,把你所有afx_msg这个宏都删掉,再来编译,有错吗,在运行,有问题吗?但是一般还是建议在编代码的时候去加上这么一个标识,这有助于代码的易读和编译器的识别。别人在读你代码的时轻松点。当然你也可以像声明其他成员函数一样的声明他们。
二. BEGIN_MESSAGE_MAP END_MESSAGE_MAP宏之间的代码添加。
我之所以在开头说到消息种类的原因就在这里,不同的消息,在这里添加的格式是不一样的。我还是不厌其烦的贴上这张图来做参考:
一:标准消息。标准消息比较简单,大部分的时候你获取会通过向导为你生成,都无需自己来动手。
在头文件中加入响应函数的声明:然后在.cpp中去ON_+消息()。
二.命令消息+通告消息。消息(控件ID,消息响应函数名字),这里有些问题希望可以注意一下,一是是函数名,不要带参数和括号,二是不要分号,可能每句结束的时候都会不自觉的去加;号 ,这里不要加的。还有声明宏的时候也是不要加分号的。这里的消息可以去MFC类库详解中去找,上面也有贴图。
三. 自定义的消息;对于自定义消息比上面的操作要来的更加繁琐一点。因为首先你没有向导了,你要纯手工了。
开始你先去头文件中声明这么一个消息。如:#define WM_MSG 9078 这样就声明了一个消息。然后去声明消息响应函数。这里的消息响应函数大部分情况下是回调函数,也就是这里的消息也大部分是回调消息。对于回调消息,那么它的格式是确定的。回调函数的格式请参见另一篇文章:回调函数的格式总结 。
然后就是BEIGIN_MESSAGE_MAP了。自定义的宏和上面其他的消息也是不一样的,如:ON_MESSAGE(WM_MSG,OnMes)
ON_MESSAGE。
好了,MFC的消息映射机制就总结到这里了。
来源:CSDN
作者:liunian17
链接:https://blog.csdn.net/liunian17/article/details/7028518