- /*
- 本文翻译自MSDN的How the Framework Searches Message Maps章节
- 对于接收到的消息,编程框架会通过消息映射表查找合适的消息处理函数。只要
- 你写了针对指定消息的消息映射入口和相应的消息处理函数,编程框架会自动地
- 调用你写的消息处理函数去处理相应的消息。
- 1:哪儿能找到消息映射
- 当你通过应用程序向导创建了一个新的框架程序,应用程序向导会为每一个它为你
- 创建的命令目标类添加消息映射。这些类包括你派生的程序实体,文档,视图,
- 框架窗口等。针对一些特定的消息和预定义的命令,向导已为其添加了消息映射
- 入口,针对你可能添加的消息处理函数,向导也准备就绪只待你添加。
- 一个类的消息映射保存在这个类的CPP文件中,典型的消息映射看起来如下:
- */
- BEGIN_MESSAGE_MAP(CMyView, CFormView)
- ON_WM_MOUSEACTIVATE()
- ON_COMMAND(ID_EDIT_CUT, &CMyView::OnEditCut)
- ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, &CMyView::OnUpdateEditCut)
- ON_BN_CLICKED(IDC_MYBUTTON, &CMyView::OnBnClickedMybutton)
- ON_WM_CREATE()
- END_MESSAGE_MAP()
- /*
- 消息映射由一系列的宏构成,BEGIN_MESSAGE_MAP和END_MESSAGE_MAP是消息映射
- 的开头和结尾。其它的宏如ON_COMMAND,填充了消息映射的内容。
- 注意消息映射中不会有分号出现。
- */
- /*
- 2:派生的消息映射
- 在消息处理的过程中,检查自身的消息映射表并不是消息映射的全部。如果在自身
- 的消息映射表中找不到合适的消息入口会如何?
- CObject
- CCmdTarget
- CWnd
- CView
- CMyView
- 上图是类CMyView的继承关系。一个CMyView对象只是一个单独的对象,但它却具有
- 其基类的所有特性。所以当一个类无法在其自身的消息映射表中找到合适的消息
- 入口时,编程框架会到其直接基类的消息映射表中继续查找。
- 宏BEGIN_MESSAGE_MAP指定了两个类名作为参数:
- */
- BEGIN_MESSAGE_MAP(CMyView, CFormView)
- /*
- 第一个参数指定了一个类名,表示当前的消息映射的所属类,第二个参数是当前
- 类的直接基类,这样就建立了一种联系,即编程框架可以到一个类的基类里继续
- 查找合适的消息入口。
- 基类的消息处理函数会被其派生类继承下来,这和虚函数是一个道理。
- 如果在任何一个基类里都无法找到合适的消息入口,那么消息会被执行默认的处理。
- 如果消息是命令类型的,编程框架会到下一个命令目标中路由消息;如果是标准
- 的消息,消息会被传递到默认的窗口过程去处理。
- 为了加速消息及其入口的匹配速度,编程框架会对最近进行了匹配项进行缓存,
- 当再次查找同一个消息的消息入口时,速度就会很快。比如对于找不到合适消息
- 入口的消息,这样子做就会很有意义。消息映射在空间效率上比虚函数高很多。
- 3:处理函数与消息的一对多关系
- 有时我们想把一些相似的消息或通知使用完全相同的方式进行处理,这种情况下,
- 就可以将一个范围内的消息或命令,通知等映射到同一个消息处理函数。消息映射
- 允许我们指定一个范围内的消息:
- 你可以将一组命令ID映射到
- 命令处理函数
- 命令更新处理函数
- 你可以将一组控件ID发出的控件消息映射到同一处理函数
- A:写一个消息映射入口
- */
- ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, &OnDoSomething)
- /*
- 消息映射入口由以下几部分构成:
- a: 指定范围的消息映射宏:
- ON_COMMAND_RANGE
- ON_UPDATE_COMMAND_UI_RANGE
- ON_CONTROL_RANGE
- b: 宏的参数:
- 前两个宏使用三个参数:
- 起始的命令ID
- 终止的命令ID
- 消息处理函数的名称
- 起始和终止间的命令ID必须是连续的。
- 第三个宏,在具有前面所述的三个参数的前提下,在前面还要求一个参数,
- 即其第一个参数是一个控件通知消息,后三个参数和前述一致。
- B:声明消息处理函数
- */
- public:
- afx_msg void OnDoSomething(UINT nID);
- /*
- 针对单一命令的消息处理函数通常没有参数。但命令更新处理函数是个
- 例外。针对一个范围的消息处理函数需要附加一个参数,一个UINT类型
- 的nID,这个参数指定了一个范围内的命令ID内,用户选择的具体是哪一个。
- 例:
- */
- ON_COMMAND_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, &OnZoom)
- public:
- afx_msg void OnZoom(UINT nID);
- /*
- nID将会是[ID_VIEW_ZOOM25,ID_VIEW_ZOOM300]中的一个。编程框架
- 为会我们自动传入。
- */
- /*
- 指定范围的命令更新消息的使用方式也是类似的,只不过其处理函数
- 不需要一个UINT类型的参数,而是一个CCmdUI*类型的参数,其内
- 包括了nID。
- */
- /*
- 指定范围的控件通知消息的使用例子如下:
- */
- ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC_BUTTON10, OnButtonClicked)
- void CRangesView::OnButtonClicked( UINT nID )
- {
- int nButton = nID - IDC_BUTTON1;
- ASSERT( nButton >= 0 && nButton < 10 );
- // ...
- }
- /*
- 对於单一的控件通知消息而言,其处理函数不需要参数,但对于指定范围的
- 控件通知消息而言,类似于指定范围的命令ID,其处理函数也需要一个UINT
- 类型的变量,用于标识具体是哪一个控件发出的通知。
- */
How the Framework Searches Message Maps(译自MSDN)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.