深入解析MFC消息路由

来源:互联网 发布:java 调用class 编辑:程序博客网 时间:2024/06/05 21:02

知道了MFC的消息路由的顺序,我们就可以重写某些虚函数,从而改变其路由顺序。比如我们想让CMyChildFrame首先响应菜单消息,就可以重写其OnCommand函数

BOOL CChildFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
UINT nID = LOWORD(wParam);
int nCode = HIWORD(wParam);
return CCmdTarget::OnCmdMsg(nID, nCode, NULL, NULL); //让其最先响应命令消息

 //return CMDIChildWnd::OnCommand(wParam, lParam);
}
加上这个函数之后,其处理顺序就变成了:

CChildFrame-->CMyView-->CMyDoc-->CMyApp-->CMainFrame.

CMainFrame其实给了两次CChildFrame处理消息的机会,一次是在CMDIFrameWnd::OnCommand()中,另一次是在CMDIFrameWnd::OnCmdMsg()中,两次最终都转变为调用CFrameWnd::OnCmdMsg.

从这也总结出应用程序使用MFC框架的两种方式,也是使用其它框架的主要方式:

1. 重写其虚函数

2. 添加消息响应函数

对于1,我认为又有两种情况:

第一种情况:框架不知道子类的名字,更不知道子类的对象的名字。只是在函数中调用虚函数,利用模板方法来实现。但前提是:必须让被调用的第一个函数的this的指针是指向子类(具体类)的对象。

第二种情况:框架知道子类的对象的名字(比如theApp全局对象,框架是知道的),这时可以直接加上::作用符来调用子类中的函数,如果子类没有重写这个函数,此调用父类的函数。

无论第一种情况,还是第二种情况,都必须解决一个问题:让接口(即框架)与接口的实现(即子类)绑定,框架定义接口,你的应用程序实现接口,说白了也就是要让框架知道你所定义的子类的名字或子类对象的名字。这在设计模式中可以通过抽象工厂+数据驱动方法来实现,在MFC中是通过声明一个全局的theApp对象,加上注册文档模板RUNTIME_CLASS(具体类名)来完成的,我认为MFC中的文档模板就相当于设计模式中的工厂+数据驱动方法

对于2.在子类中添加消息响应函数。

  消息响应函数不是虚函数,函数名字也是用户自已取的,并且函数是在子类中(框架并不知道这个子类的名字),那框架是如何知道调用这个函数的呢? 

  这是因为在我们的子类中,在DECLARE_MESSAGE_MAP,BEGIN_MESSAGE_MAP,END_MESSAGE_MAP中完成了消息映射表的定义,表的填充并重写了CCmdTarget的虚函数GetMessageMap.

所以在CCmdTarget中能够获得我们的子类的消息映射表,从而根据消息映射表来对消息进行处理。

设计模式: ”职责链”+“模板方法”+”文档模板”(工厂+数据驱动)+”观察者”

通过分析,我们可以看出MFC中所使用的最多的几种设计模式

1."职责链"(主要用在消息路由)

2.模板方法

3.文档模板(实质就是工厂+数据驱动,如果是在Java中,就不需要这样做了,因为Java中有反射API,可以直接由类的名字,字符串来生成对象)-->而这一过程的实质就是完成:接口与接口的实现的绑定

4.观察者模式(文档/视图)

原创粉丝点击