How the Framework Searches Message Maps(译自MSDN)

  1. /*
  2.     本文翻译自MSDN的How the Framework Searches Message Maps章节
  3.     对于接收到的消息,编程框架会通过消息映射表查找合适的消息处理函数。只要
  4.     你写了针对指定消息的消息映射入口和相应的消息处理函数,编程框架会自动地
  5.     调用你写的消息处理函数去处理相应的消息。
  6.     1:哪儿能找到消息映射
  7.     当你通过应用程序向导创建了一个新的框架程序,应用程序向导会为每一个它为你
  8.     创建的命令目标类添加消息映射。这些类包括你派生的程序实体,文档,视图,
  9.     框架窗口等。针对一些特定的消息和预定义的命令,向导已为其添加了消息映射
  10.     入口,针对你可能添加的消息处理函数,向导也准备就绪只待你添加。
  11.     一个类的消息映射保存在这个类的CPP文件中,典型的消息映射看起来如下: 
  12. */
  13. BEGIN_MESSAGE_MAP(CMyView, CFormView)
  14.     ON_WM_MOUSEACTIVATE()
  15.     ON_COMMAND(ID_EDIT_CUT, &CMyView::OnEditCut)
  16.     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, &CMyView::OnUpdateEditCut)
  17.     ON_BN_CLICKED(IDC_MYBUTTON, &CMyView::OnBnClickedMybutton)
  18.     ON_WM_CREATE()
  19. END_MESSAGE_MAP()
  20. /*
  21.     消息映射由一系列的宏构成,BEGIN_MESSAGE_MAP和END_MESSAGE_MAP是消息映射
  22.     的开头和结尾。其它的宏如ON_COMMAND,填充了消息映射的内容。
  23.     
  24.     注意消息映射中不会有分号出现。
  25. */
  26. /*
  27.     2:派生的消息映射
  28.     在消息处理的过程中,检查自身的消息映射表并不是消息映射的全部。如果在自身
  29.     的消息映射表中找不到合适的消息入口会如何?
  30.         CObject
  31.         CCmdTarget
  32.         CWnd
  33.         CView
  34.         CMyView
  35.     上图是类CMyView的继承关系。一个CMyView对象只是一个单独的对象,但它却具有
  36.     其基类的所有特性。所以当一个类无法在其自身的消息映射表中找到合适的消息
  37.     入口时,编程框架会到其直接基类的消息映射表中继续查找。
  38.     宏BEGIN_MESSAGE_MAP指定了两个类名作为参数:
  39. */
  40. BEGIN_MESSAGE_MAP(CMyView, CFormView)
  41. /*
  42.     第一个参数指定了一个类名,表示当前的消息映射的所属类,第二个参数是当前
  43.     类的直接基类,这样就建立了一种联系,即编程框架可以到一个类的基类里继续
  44.     查找合适的消息入口。
  45.     基类的消息处理函数会被其派生类继承下来,这和虚函数是一个道理。
  46.     如果在任何一个基类里都无法找到合适的消息入口,那么消息会被执行默认的处理。
  47.     如果消息是命令类型的,编程框架会到下一个命令目标中路由消息;如果是标准
  48.     的消息,消息会被传递到默认的窗口过程去处理。
  49.     为了加速消息及其入口的匹配速度,编程框架会对最近进行了匹配项进行缓存,
  50.     当再次查找同一个消息的消息入口时,速度就会很快。比如对于找不到合适消息
  51.     入口的消息,这样子做就会很有意义。消息映射在空间效率上比虚函数高很多。
  52.     3:处理函数与消息的一对多关系
  53.     有时我们想把一些相似的消息或通知使用完全相同的方式进行处理,这种情况下,
  54.     就可以将一个范围内的消息或命令,通知等映射到同一个消息处理函数。消息映射
  55.     允许我们指定一个范围内的消息:
  56.         
  57.         你可以将一组命令ID映射到
  58.             命令处理函数
  59.             命令更新处理函数
  60.         你可以将一组控件ID发出的控件消息映射到同一处理函数
  61.         A:写一个消息映射入口 
  62.         */
  63.         ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, &OnDoSomething)
  64.         /*
  65.             消息映射入口由以下几部分构成:
  66.             
  67.             a: 指定范围的消息映射宏:
  68.             
  69.             ON_COMMAND_RANGE
  70.             ON_UPDATE_COMMAND_UI_RANGE
  71.             ON_CONTROL_RANGE
  72.             b: 宏的参数:
  73.             前两个宏使用三个参数:
  74.                 起始的命令ID
  75.                 终止的命令ID
  76.                 消息处理函数的名称
  77.             起始和终止间的命令ID必须是连续的。
  78.             第三个宏,在具有前面所述的三个参数的前提下,在前面还要求一个参数,
  79.             即其第一个参数是一个控件通知消息,后三个参数和前述一致。
  80.         
  81.         B:声明消息处理函数
  82.         */
  83.             public:
  84.                 afx_msg void OnDoSomething(UINT nID);
  85.             /*
  86.             针对单一命令的消息处理函数通常没有参数。但命令更新处理函数是个
  87.             例外。针对一个范围的消息处理函数需要附加一个参数,一个UINT类型
  88.             的nID,这个参数指定了一个范围内的命令ID内,用户选择的具体是哪一个。
  89.             例:
  90.             */
  91.             ON_COMMAND_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, &OnZoom)
  92.             public:
  93.                 afx_msg void OnZoom(UINT nID);
  94.             /*
  95.                 nID将会是[ID_VIEW_ZOOM25,ID_VIEW_ZOOM300]中的一个。编程框架
  96.                 为会我们自动传入。
  97.             */
  98.             /*
  99.                 指定范围的命令更新消息的使用方式也是类似的,只不过其处理函数
  100.                 不需要一个UINT类型的参数,而是一个CCmdUI*类型的参数,其内
  101.                 包括了nID。
  102.             */
  103.             /*
  104.                 指定范围的控件通知消息的使用例子如下:
  105.             */
  106.     ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC_BUTTON10, OnButtonClicked)    
  107.     void CRangesView::OnButtonClicked( UINT nID )
  108.     {
  109.         int nButton = nID - IDC_BUTTON1;
  110.         ASSERT( nButton >= 0 && nButton < 10 );
  111.         // ...
  112.     }
  113.     /*
  114.         对於单一的控件通知消息而言,其处理函数不需要参数,但对于指定范围的
  115.         控件通知消息而言,类似于指定范围的命令ID,其处理函数也需要一个UINT
  116.         类型的变量,用于标识具体是哪一个控件发出的通知。
  117.     */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章