我们知道命令消息就是由菜单栏,工具栏或加速键(我们一般叫做快捷键)产生的消息.
前面有讲过标准消息就由其对应的CWnd类的子类处理就OK,子类不处理就回溯回父类.不用转给其他类处理.但命令消息不同,只要是继承自CCmdTarget的类都可以处理,也就是说前面提到的5个核心的类(CWinApp,CSingleDocTemplate,CFrameWnd,CView,CDocument)都可以处理它.
那一个命令消息发出来到底谁去处理呢 ?
首先你猜想着要是不是上面5个类都有对应的宏去映射下就都可以处理.也就是5个类同时处理? 显然不是这样.一次只让一个类去处理的.于是就会给这5个类排下优先次序.先看前面有对应的消息映射宏不,有的话就让该类来处理,排名靠后的类就不管他们了.反正就这样依次检查.
消息路由的次序
这里以SDI项目(single document inerface)为例来说下.假如点下菜单栏中的File-->Open发出一个消息,看下这消息是怎么被处理的.
假如继承自CWinApp,CFrameWnd,CView,CDocument的4个类中都写上宏
ON_COMMAND(ID_FILE_OPEN, OnOpen);
定义了函数afx_msg void OnFileOpen();
这样一来说明这4个类都有能力来处理命令消息了,但有能力处理未必就真让它处理.就像你觉得自己有能力当个啥领导了,但大领导未必就真让你当,最是把你作为候选人而已.
首先我们知道那些菜单,工具栏都是由CFrameWnd创建的.但实际上最先不是由它来处理.(实际上准确的讲是这4个类的子类来处理,为了讨论方便就说父类的名字好了)
1.先是由CView来处理,你Debug的时候会看到执行到CView的OnFileOpen函数.执行完这函数后其他类中相同的OnFileOpen不会被执行到.
2.如果CView没有处理则由CDocument来处理.你可以把CView中的宏ON_COMMAND(ID_FILE_OPEN, OnOpen)注释掉.这样debug下就发现会执行CDocument中的函数OnFileOpen了
3.如果CDocument也没有处理则由CFrameWnd来处理.同样你把CDocument的宏ON_COMMAND(ID_FILE_OPEN, OnOpen)注释掉.这样debug下就发现会执行CFrameWnd中的函数OnFileOpen了
4.如果CDocument也没处理则由CWinApp来处理.你把CFrameWnd的宏ON_COMMAND(ID_FILE_OPEN, OnOpen)注释掉.这样debug下就发现会执行CWinApp中的函数OnFileOpen了
所以路由的顺序是1.CView -- > 2.CDocument --->3.CFrameWnd -->3.CWinApp
当然如果是MDI项目的话顺序就不太一样.是下面这样
1.CView --> 2.CDocument -->3.CMDIChildWnd--> 4.CWinApp -->5.CMDIFrameWnd
(注:貌似有些书上讲是CWinApp最后一个,但实际上测试的时候发现不是.你反正自己在VS中debug测下就知道了)