MFC--自定義消息

在windows程序中,消息是一個重要的概念,最常見的消息一般都是以WM_開頭,WM就是window message,窗口消息的縮寫,通過處理標準的windows消息,我們可以改變窗口的外觀,如使用WM_ERASEBKGND消息可以改變窗口默認的窗口背景,窗口每次需要繪製窗口的背景的時候,就會發送一次這個消息,如果我們處理這個消息,我們就可以繪製我們自己的特性化的背景,如果不處理,默認窗口過程就會處理,繪製背景。通過處理標準的windows消息,我們可以對用戶的輸入做出響應,如WM_LBUTTONDOWN,當鼠標按下的時候,就可以對用戶的操作作出響應,通過命令消息WM_COMMAND消息,可以獲取來自菜單,按鈕的命令。另外,控件還有自己的notification消息,當控件的狀態發生改變的時候,如點擊按鈕,點擊編輯框,選擇一個列表框項目時,就會發送相應的消息,通過處理消息,就可以對獲取控件的一些消息,做出一些處理。在sdk中還有一種消息,也是用於控件的,也是通過發送消息來控制控件的屬性和操作,而這個在MFC中變成了成員函數,但是底層的原理還是一樣的。消息的作用還有很多,我們不能單一的去理解消息這個概念,一方面,我們可以通過閱讀msdn可以深入的學習消息,另一方面,我們可以通過在使用的過程中,加深對消息的理解。除了使用上面說的這些windows提供的預定義消息(系統消息)之外,我們也可以使用我們自定義的消息。

每個消息有一個ID,對於自定義消息,我們在定義的時候,也要定義一個ID,而這個ID的範圍是有要求的,可以是WM_USER (0x0400) 到 0x7FFF,也可以是 WM_APP (0x8000) 到0xBFFF,別的ID範圍呢,系統保留。在使用的時候,通常都是以WM_USER+X,WM_APP+X或是在定義消息ID的時候,有兩種方法:

第一種方法是通過常量聲明幅值的方法,也就是常量的使用方法,因爲一個消息的ID就是一個常量,確定之後,就不能改變,因此,可以使用定義常量的方法來爲一個消息附上ID,如下:

const UINT WM_MYMESSAGE1=WM_APP+1;

第二種方法是通過#define,如下:

#define WM_MYMESSAGE2 WM_APP+2

通過這兩種方法,我們就可以在爲一個消息指定ID。下面是要說說,上面這兩句定義消息ID的表達式所放的位置的不同所產生的使用方法的不同。下面以實例來說明:

第一種情況,當我把定義消息ID的表達式放在了頭文件MyView.h中


當我在SINView.cpp文件中接收和處理這兩個消息時,必須事先包含聲明兩個消息ID的頭文件,這裏是MyView.h。否則,在cpp中處理的時候,就是出現語法錯誤,提示未聲明的標示符。

第二種情況,如果我們由於一些原因,不能包含聲明消息ID的頭文件,例如,如果我們包含了,就會出現互相包含的情況,就會造成錯誤,或是,將在發送這個消息的cpp文件和接受處理這個消息的cpp文件中定義這兩個消息的ID,那麼這個時候,我們必須在兩個地方聲明和幅值消息ID,一個地方是發送的類的源文件或頭文件中,另一個地方是接收和處理這個自定義消息的源文件中。例如,WM_MYMESSAGE3,我在MyView.h或是MyView.cpp中進行聲明,因爲我要從MyView.cpp中發送這個消息,如圖:


在接收消息的地方,我再次定義一次,可以直接複製上次定義的,我要在SINView.cpp中接收和處理,於是在這個文件的開頭,如下圖:


現在已經定義好了消息的ID,接下來是發送消息,發送消息,一般是是用SendMessage和PostMessage,SendMessage必須要等到這個消息被處理並返回之後纔會結束執行,否則會一直等待,如果消息一直得不到處理,函數一直等待,就會造成發送消息的線程阻塞。PostMessage是將消息發送之後,就立即返回,不管消息是否到達目的地,處理。如果在單線程程序中,我們最好是用PostMessage,用SendMessage容易造成線程鎖死。另外,在MFC中使用這兩個函數,如果直接使用,第一個參數就是要發送的消息,這樣只能向本窗口發送消息,如果在MFC中使用::PostMessage,這樣就是使用的是win32函數的api,第一個參數是目標窗口句柄,就可以向任意窗口發送消息。

下面說說如何處理髮送的消息,首先介紹一種最爲簡單的處理方法,這種方法和在win32 sdk中的窗口過程一樣,通過switch/case語句來處理.在MFC窗口類都有一個WindowProc虛函數,當這個窗口的消息進入這個窗口的消息映射之前,會首先通過這個虛函數,因此,我們在這裏就可以攔截處理我們的自定義消息,甚至是別的任何消息,當然,標準窗口消息仍然是推薦使用MFC的消息映射的方法來處理。如下圖:


使用這種方法,有一點很重要,那就是最後那一句return語句:return CView::WindowProc(message, wParam, lParam);這樣保證別的消息可以正確處理。這種處理方式和win32 sdk中的窗口過程處理消息的方式是一樣的。

接着介紹一種MFC標準的自定義消息處理的方式,也就是是用ON_MESSAGE宏。使用這種方式,就和我的博文"MFC-消息機制"中描述的消息處理方式一樣,要使用這種處理方式,首先要聲明一個消息響應函數原型,接着添加消息映射,最後實現消息響應函數。我們一步一步來看,首先看ON_MESSAGE宏的原型:

ON_MESSAGE(message, memberFxn)

第一個參數是消息ID,第二個參數消息響應函數。現在,針對WM_MYMESSAGE3消息,我們使用這種處理方式。首先在CSINView類中聲明一個消息響應函數:

afx_msg LRESULT OnMyMessage3(WPARAM wParam, LPARAM lParam);

消息響應函數的名稱由自己確定,這裏我使用的是OnMyMessage3。在聲明這個消息響應函數的時候,一般就是按照這個樣式,而且一般聲明爲protected。

接着是消息添加消息映射,使用ON_MESSAGE,如下:


最後是實現消息響應函數,在SINView.cpp中,如下:


通過ON_MESSAGE宏,當窗口接收到消息的時候,就會自動調用我們的消息響應函數了。

以上就闡述了一下,在MFC自定義消息的使用方法,下面是效果圖:


最後在說說消息過濾的問題,使用過win32 sdk編寫程序的人都知道,可以在使用while從消息隊列中獲取消息的時候,在派發消息到窗口之前,可以做一個消息過濾,在MFC這裏也可以,CWinApp有一個虛函數CWinApp::PreTranslateMessage,這個虛函數就是消息循環獲取消息,派發之前,就調用這個虛函數,我們就可以在這個虛函數中,攔截過濾一些消息,主要是通過這個虛函數的參數,一個消息結構體,來判斷要過濾的消息。一個是判斷句柄,一個是判斷消息id。

本文中涉及到的信息,如有疑問,請參考msdn。

author email:[email protected] 

本文代碼:http://download.csdn.net/detail/xinzhiyounizhiyouni/6680781 

windows7 vs2010環境下

發佈了46 篇原創文章 · 獲贊 5 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章