- /*
- 本文翻譯自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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.