在元文件中增加的三处代码
(1)消息响应函数原型
c**类的头文件中
C++ Code
1 2 3 |
//{{AFX_MSG(CLesson4_2View) afx_msg void OnLButtonDown(UINT nFlags, CPoint point); //}}AFX_MSG |
AFX_MSG注释宏,他们实际上是宏,但因为前面加了注释符,所以称之为注释宏,机上afx_msg限定符,这也是一个宏,表示这个函数是一个消息响应函数的声明。
(2)ON_WM_LBUTTONDOWN消息映射宏
C++ Code
1 2 3 4 5 6 7 8 9 10 |
BEGIN_MESSAGE_MAP(CLesson4_2View, CView) //{{AFX_MSG_MAP(CLesson4_2View) ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() |
在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()这两个宏之间定义了CDrawView类的消息映射表,其中有一个ON_WM_LBUTTONDOWN这个消息映射宏,这个宏的作用就是把鼠标左键按下消息与一个消息响应函数关联起来(本例中把WM_LBUTTONDOWN与ON_WM_BUTTONDOWN函数关联起来)通过这种机制,一旦有消息产生,程序就会调用响应的消息响应函数来进行处理。
(3)消息响应函数的定义
在源文件中,可以看到ONLButtonDown函数的定义
C++ Code
1 2 3 4 5 6 7 |
void CLesson4_2View::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default MessageBox("view clicked"); CView::OnLButtonDown(nFlags, point); } |
总结:
消息路由可以有多用实现方式,其中一种可能的实现方式是,在基类中针对每一个消息定义一个虚函数,当子类需要对某个消息进行处理时,只需要重写基类响应的虚函数即可,当在程序中调用这个函数时,根据多态性原理,如果子类重写了该函数,就调用子类的这个函数,否则就调用父类的相应函数,通过这种方式也可以完成消息的路由。
但是这样是不可取的,因为虚函数必须由一个虚函数表来实现,在应用程序中使用的每个派生类,系统都要为他们分配一个虚函数表,并且不管基类中虚函数是否确实在派生类中重写,这个表都要为基类的每一个虚函数提供4个字节的输入项,MFC中类的派生层很多,这样做,将使MFC类及其派生类都背着一个很大的虚拟函数表。
MFC消息映射机制的具体实现方法是:在每个能接受和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表。在消息映射表中,消息与对应的消息处理函数指针是成对出现的。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息处理时,程序值要搜索该消息静态表,查看表中是否有该消息,就知道该类能否处理此消息。如果能处理该消息,则同样依照静态表能很容易找到并调用对应的消息处理函数
首先判断消息是否有消息响应函数
判断方法是在响应窗口类中查找所需的消息响应函数,因为传递给WindowProc函数的是窗口子类指针,所以OnWndMsg函数会到响应的子类文件中查找,看看DECLARE_MESSAGE_MAP()宏之上,两个AFX_MSG注释宏之间是否有相应的消息响应函数原型声明,再到子类的文件中,看看BEGIN_MEGGAGE_MAP和END_MEGGAGE_MAP()这两个宏之间是否有相应的消息映射宏.
如果通过上述步骤,找到了消息响应函数,那么就接着调用该响应函数,对消息进行处理
如果在子类中没有找到消息响应函数,那么就交给基类进行处理