MFC中子控件響應鍵盤消息

在MFC的窗口和控件編程時,經常需要使某個控件主動響應用戶的鍵盤消息,哪怕該控件並沒有輸入功能。
爲方便說明,假設你的主窗口爲A,需要相應鍵盤消息的子控件爲B爲一個圖片控件(Picture control)。
此時,你需要做如下工作:


1. 派生一個自己的類作爲B的類
Picture control默認的ID是IDC_STATIC,這種ID是不能定義變量的,因此把該ID改成別的名字,如IDC_TEST。
然後添加一個控件變量,先選擇CStatic,確認,讓MFC生成相應代碼(主要是DDX_Control等代碼。如果你熟悉MFC,也可以不使用類嚮導自己寫)。
最後新建一個MFC類CMyStatic,繼承自CStatic,將代碼中的CStatic替換成CMyStatic。


2. 重寫CMyStatic的PreTranslateMessage虛函數
PreTranslateMessage顧名思義,是在消息路由之前,對消息進行預處理。
注意最重要的是PreTranslateMessage的返回值,默認是FALSE。如果返回TRUE,該消息將無法再往下傳遞!
按鍵消息的路由路徑,可由下圖所示:
按鍵消息路由示意圖
主消息循環線程類CWinThread收到按鍵消息後,由當前焦點窗口(此時爲子控件)的PreTranslateMessage預處理後再逐個向父窗口傳遞,任何時候返回TRUE,都會終止消息進一步的處理。
此鏈式處理直到頂級窗口(理解爲其父窗口爲桌面)的預處理完成後,再由主消息循環線程類CWinThread::DispatchMessage分發給焦點窗口(圖中OnWndMsg響應該消息)。
鍵盤的消息可以在OnChar中響應,也可以在OnKey*中響應。取決於應用的需求。
可以結合CWinThread中的PumpMessage代碼加深一下理解:

    GetMessage(...);
    if ( !AfxPreTranslateMessage(...)// 預處理!實現爲從子到父鏈式處理
    {
        // 如果預處理返回FALSE,則分發消息
        ::TranslateMessage(...);
        ::DispatchMessage(...);
    }

按鍵消息從焦點控件到父窗口先預處理一遍再分發,目的就是爲了讓整個父子窗口體系都能獲得處理消息的機會,給程序員截獲和處理消息提供最大的靈活性。掌握和理解這個消息路徑是非常重要的。


3. 設置窗口焦點
由於在消息路由中,鍵盤消息永遠只能傳給當前焦點所在的窗口或空間。因此,需要在A的OnInitDialog中設置控件B作爲窗口焦點。
注意OnInitDialog的返回值!如果返回TRUE,則表示無論你代碼設置了誰爲焦點,最終都使用A窗口的默認控件作爲焦點!因此一定要返回FALSE!

    // 設置test控件爲焦點,以便相應鍵盤事件
    m_test.SetFocus();

    // 返回TRUE則使用默認的焦點(按鈕),因此必須返回FALSE
    return FALSE;  // return TRUE  unless you set the focus to a control

MFC自動生成的代碼中隱含了大量細節。如各個虛函數的功能,每個函數的返回值等等。如果弄錯,都會導致完全不同的結果。這需要編碼者對MFC的低層細節具備較高的掌控能力。
當然,這也是MFC備受詬病的地方。
本文實例代碼下載鏈接爲:http://download.csdn.net/detail/lsldd/9533217

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章