MFC的单文档架构,有四个类(这里忽略About对话框类):
- MainFrame
- App
- Doc
- View
这四个类和MVC设计模式的关系如下:
- MainFrame代表着MVC的C (Control)。
- App可以理解为对hInstance的封装。
- Doc对应着MVC的M (Model)。
- View对应着MVC的V (View)。
这四个类全部继承自CCmdTarget类,所以它们都具有处理消息的能力。问题是:同一个WM_COMMAND消息,谁先处理,谁后处理(4个类对消息处理的优先级问题)?
现在做试验分析,首先要明确WM_COMMAND消息的产生方式。以下三种情况都能产生WM_COMMAND消息:
- 菜单选项的点击
- 控件状态的改变(例如按钮按下)
- 键盘快捷键的按下
首先增加一个菜单选项:
然后在每个类中,都进行如下操作:进入类向导,在Command标签中增加关于此菜单项的处理函数:
在每个函数内部写一个AfxMessageBox()
函数,作为标记:
这样,现在每个类都有了标记用的弹框提示。运行程序,点击此菜单项,就知道这四个类对WM_COMMAND消息处理的优先权了:
结果是View类对VM_COMMAND消息作出了响应。经测试,一旦一个类处理了消息,其他类就不会处理了(也就是说只会弹出一个对话框(刚才设置了4个AfxMessageBox)),这四个类的优先级顺序为:
- View
- Doc
- MainFrame
- App
现在探究这个顺序的原因。研究的方法是在CSingleView::OnHelpTestcmd()
函数里下断点,断下来之后分析栈回溯:
分析之后找到原因:CFrameWnd::OnCmdMsg()函数内部,通过顺序结构规定了这四个类对WM_COMMAND消息的处理优先级:
从代码以及注释中,可以清楚地看到这个优先级:View第一,下一个是MainFrame,最后是App。Doc哪里去了?Doc和View绑定到一个函数里去了,继续看栈中的函数CView::OnCmdMsg()
:
这里可以看到对Doc的处理(紧跟着View)。