




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第3章 消 息 處 理第1章討論了MFC用戶界面的基本要素:窗口、窗口類和 CWnd;第2章討論了 MFC 庫的其他類,尤其是那些 MFC應(yīng)用程序內(nèi)核的類。在本章中, 討論 MFC類和它們的窗口怎樣進行互相通信的。我們發(fā)現(xiàn)有三種類型的消息:窗口、命令 (d)和控件通知(Control Notification),并且這些消息既可以發(fā)送 (sent),也可以寄送(post);接著,將跟蹤一個被MFC窗口進程處理的消息;最后,將討論重定向消息的 。3.1 發(fā)送或寄送一個消息第1章已提及,每個窗口使用窗口進程處理發(fā)送給它的消息。消息可以來自系統(tǒng)、你的應(yīng) 用程序或別的應(yīng)用程序。消息告訴窗口進程執(zhí)行某個
2、任務(wù) (如初始化 、繪制或銷毀一個窗口等),或者通知它發(fā)生某個 (如鼠標正單擊窗口)。系統(tǒng)或應(yīng)用程序有兩種傳輸消息的 :發(fā)送消息或寄送消息。3.1.1 發(fā)送一個消息發(fā)送一個消息時,直接調(diào)用窗口的窗口進程。通信是即時的,直到窗口進程為調(diào)用函數(shù) 返回一個結(jié)果后,應(yīng)用程序才能繼續(xù)。3.1.2 寄送一個消息窗口對象寄送一個消息時,把消息發(fā)送到擁有那個窗口的應(yīng)用程序消息隊列中。一有空閑,應(yīng)用 程序就搜索消息隊列,并在消息隊列中處理消息,即從隊列中刪除它們,并將它們發(fā)送到即 定窗口。通信將可能延遲,直到目標應(yīng)用程序獲得處理消息的時間。調(diào)用函數(shù)發(fā)送消息后即 返回,但結(jié)果只是表示消息寄送 與否,而不是被調(diào)用窗
3、口進程的結(jié)果 (見圖3-1)。被發(fā)送的消息直接調(diào)用該窗口的窗口進程被寄送的消息延遲在消息泵消息n+1 消息n+2 消息n+3 消息n+4WndProc地址當應(yīng)用程序空閑時, 抽出寄送到隊列中 的消息并調(diào)用該窗 口的窗口進程應(yīng)用程序消息隊列中消息隊列圖3-1 發(fā)送消息時通信是即時的,而寄送消息時通信可能延遲3.1.3 發(fā)送一個消息與寄送一個消息的比較鼠標和鍵盤消息通常是寄送的,而所有其他消息通常都是發(fā)送的。在消息隊列中,寄送第3章 消 息 處 理49的消息接受特殊的鼠標和鍵盤處理。通常,應(yīng)該盡量發(fā)送一個消息,除非想把動作延有鼠標和鍵盤消息被處理之后。所3.2怎樣使用MFC發(fā)送一個消息用MFC發(fā)送
4、一個消息的是,首先,應(yīng)獲取接收消息的 CWnd類對象的指針;然后,調(diào)用CWnd的成員函數(shù)SendMessage( )。LRESULT Res=pWnd-SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);pWnd指針指向目標CWnd類對象。變量Msg是消息, wParam和lParam變量包含消息的參數(shù),如鼠標單擊哪里或選擇了什么菜單項。目標窗口返回的消息結(jié)果放在變量 Res中。發(fā)送消息到一個沒有CWnd類對象的窗口,可以用下列目標窗口的句柄直接調(diào)用 Windows API:LRESULT Res=:SendMessage(HWND hWnd
5、 , UINT Msg , WPARAM wParam , LPARAM lParam);這里的hWnd是目標窗口的句柄。3.3 怎樣用MFC寄送一個消息用MFC寄送一個消息與發(fā)送一個消息幾乎相同,但寄送時用 PostMessage( ) ,而不是用SendMessage( );返回值Res也不一樣, Res不是一個由目標窗口返回的值,而是一個布爾值, 用來表示消息是否 地放到消息隊列中。檢索一個寄送消息正常情況下,一旦消息被寄送后,應(yīng)用程序在 發(fā)送它。但是在特殊情況下,需要你去刪除一個消息,例如想在應(yīng)用程序接收到某種消息之前停止應(yīng)用程序。有兩種 可以從應(yīng)用程序消息隊列中刪除一個消息,但這兩種
6、 都沒有涉及 MFC。 第法:在不干擾任何事情之下窺視消息隊列,看看一個消息是否在那里。BOOL res=:PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); 第二種 :實際上是等待,一直等到一個新的消息到達隊列為止,然后刪除并返回 該消息。BOOL res=:GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);在這兩種 中,變量hWnd指定要截獲消息的窗口,如果該
7、變量設(shè)為 NULL,所有窗口消息將被截獲。wMsgFilterMin和wMsgFilterMax變量與SendMessage( )中的變量Msg相對應(yīng), 指定查看消息的范圍。如果用“ 0, 0 ”,則所有的消息被截獲。如果用 WM_KEYFIRST, WM_KEYLAST或WM_MOUSEFIRST, WM_MOUSELAST,則所有鍵盤或鼠標的消息將被截獲。w R e m o v e M s g變量指定PeekMessage( )是 否應(yīng)該真正地從隊列中刪除該消息。(GetMessage( )總是刪除消息)。該變量可以取兩個值: PM_REMOVE,PeekMessage( )將刪除消息。
8、PM_NOREMOVE,PeekMessage( )將把消息留在隊列里,并返回它的一個拷貝。當然,如果把消息留在消息隊列中,然后再次調(diào)用 PeekMessage( ) 查看相同類型的消息, 則將返回完全相同的消息。lpMsg變量是一個指向MSG結(jié)構(gòu)的指針, MSG包含檢索到的消息。typedef struct tagMSG HWNDhwnd; / window handle message is intended for UINTmessage;WPARAM wParam; LPARAMlParam;DWORDtime;/ the time the message was put in the
9、 queue POINTpt;/ the location of the mouse cursor when the/ message was put in the queue MSG;3.4 三種類型的消息在MFC應(yīng)用程序中傳輸?shù)南⒂腥N類型:窗口消息、命令消息和控件通知。3.4.1 窗口消息窗口消息(Window Message)與窗口的內(nèi)部有關(guān),如創(chuàng)建窗口、繪制窗口和銷毀窗口等。通常,消息是從系統(tǒng)發(fā)送到窗口,或從窗口發(fā)送到窗口。當用Send Message()或Post Message()發(fā)送一個窗口消息時,變量 Message、w Param和lParam的格式如下:Messagew
10、ParamlParamWM_定義令定義令WM_可以是許多窗口消息之一,如下列窗口: WM_CREATE,告訴窗口初始化。 WM_PAINT,告訴窗口繪制。 WM_MOUSEMOVE,告訴窗口鼠標移經(jīng)它。有關(guān)某些公共窗口消息,參見附錄B。若需要窗口消息的完全的列表,請參考 MFC文檔。3.4.2 命令消息命令消息與處理用戶請求相關(guān),當用戶單擊一個菜單項或工具欄時,命令消息產(chǎn)生, 并被發(fā)送到能處理該請求的類對象(如,裝載文件、編輯文本和保存選項等)。當用SendMessage( )或PostMessage( )發(fā)送窗口消息時,變量Message、wParam和lParam的格式如下:Message
11、wParamlParamWM_D0d ID0d ID要么是選中菜單項的ID,要么是被單擊的工具欄按鈕。注意d ID不能大于一個字長,如果使它大于一個字長,系統(tǒng)就只用 0來填充高位字。某些控件通知也用WM_D消息,區(qū)別兩種消息的唯一是lParam是否為NULL。3.4.3 控件通知通常,控件通知在某些重要發(fā)生時,由控件窗口發(fā)送到父窗口,如打開一個組合框。控件通知為父窗口進一步子窗口提供了機會。例如,打開一個組合框時,父窗口可以用 組合框初建時得不到的消息填充它。控件通知經(jīng)歷了一個演變過程,因而 SendMessage( )的變量Message、wParam和lParam有三種格式。1. 第一控件
12、通知格式第一控件通知格式只是窗口消息的子集。MessagewParamlParamWM_定義令定義令WM_可以是下面消息中的任何一種: WM_PARENTNOTIFY表示一個控件窗口要么已被建立或銷毀,要么鼠標已單擊了該 窗口。 WM_CTLCOLOR、WM_DRAWITEM、WM_MEASUREITEM、WM_DELETEITEM、WM_CHARTOITEM、WM_VKEYTOITEM或WM_COMPAREITEM都是送往父窗口的 消息,用來繪制自身的控件窗口。 WM_HSCROLL或WM_VSCROLL由滾動條控件發(fā)送,通知父窗口滾動窗口。2. 第二控件通知格式第二控件通知格式使用WM_D
13、消息,與命令消息共享。MessagewParamlParamWM_ DXN_ 控件ID窗口句柄lParam變量用來區(qū)分是命令消息還是控件通知??丶ㄖ?lParam中有一個有定義的句柄,用來標識發(fā)出通知的控件;而命令消息中 lParam為NULL。XN_值因發(fā)出通知的控件不同而不同,例如, XN_值為EN_CHANGE,告訴父窗口顯示在編輯框控件中的文本已發(fā)生變化。還有其他一些例子列在附錄 B中。3. 第三控件通知格式第三控件通知格式也是最靈活 格式,它用 WM_NOTIFY消息。MessagewParamlParamWM_NOTIFY控件ID指向NMHDR的指針lParam值指向一個結(jié)構(gòu),
14、該結(jié)構(gòu) 有關(guān)制作該通知的控件的任何內(nèi)容,而不受空間和 類型的限制,該結(jié)構(gòu)叫做NMHDR。typedef struct tagNMHDR HWND hwndFrom; / Window handle of Control Window/ making the notification.UINT idFrom;/ Control ID of Control Window/ making the notification.UINT code;/ notification code ex: the user/ has clicked the Control Window NMHDR;NMHDR代表通知
15、消息頭(Notification Message Header)。為什么要這個頭?因為某些控件用NMHDR作為頭發(fā)送一個更大結(jié)構(gòu)的消息,即使那些不知道更大結(jié)構(gòu)內(nèi)容的函數(shù)還是能處理通知頭。3.5 MFC怎樣接收一個寄送的消息MFC處理一個寄送和發(fā)送消息的唯一明顯不同是寄送的消息要在應(yīng)用程序的消息隊列中 花費一些時間。在消息泵(message pump)彈出它之前,它要一直在隊列中。消息泵MFC應(yīng)用程序中的消息泵在CWinApp的成員函數(shù)Run( ) 中。應(yīng)用程序開始運行時, Run( ) 就被調(diào)用, Run( ) 把時間分割成兩部分。一部分用來執(zhí)行 處理,如取消臨時 CWnd對象; 另一部分用來
16、檢查消息隊列。當一個新的消息進來時, Run( )抽取它 即用GetMessage( )從隊列中取出該消息,運行兩個消息翻譯函數(shù),然后用 DispatchMessage( ) 函數(shù)調(diào)用該消息預(yù)期的目標窗口進程(見圖3-2)??臻e處理 (內(nèi)務(wù)處理、處理)新的消息出現(xiàn)在消息隊列中?翻譯字符消息發(fā)送消息到窗口進程圖3-2 消息泵執(zhí)行處理并檢查消息隊列消息泵調(diào)用的兩個翻譯函數(shù)是PreTranslateMessage( )和:TranslateMessage( )。目標窗口的MFC類可調(diào)用PreTranslateMessage在發(fā)送消息給它之前進行消息翻譯,例如, CFrameWnd用PreTransl
17、ateMessage( ) 將 鍵(如,Ctrl+S 文件)轉(zhuǎn)換為命令消息。翻譯前的消息通常被處理掉,而翻譯后的消息(如果有的話)將被重新寄送到隊列里。:TranslateMessage是一個窗口函數(shù),將原始鍵碼轉(zhuǎn)換為鍵字符。消息一旦被DispatchMessage( ) 發(fā)送, MFC處理它就像處理SendMessage( ) 發(fā)送的消息一樣。3.6 MFC怎樣處理一個接收到的消息處理接收到的消息的目的非常簡單:將消息指向一個函數(shù),該函數(shù)通過消息中的消息標 識符處理它。非MFC窗口用簡單的case語句來實現(xiàn)該目標,每個case語句執(zhí)行一些函數(shù),或調(diào)用其他一些函數(shù)。MainWndProc(HW
18、ND hWnd, UINT message, W PARAM wParam, LPARAM lParam)switch(message)case WM_CREATE: : :break;case WM_PAINT: : :break; default:return(DefWindowProc(hWnd, message, wParam, lParam);return(NULL);任何遺漏的消息將被傳輸?shù)揭粋€默認的消息處理函數(shù),但是, case語句不能很好地適應(yīng)C+和封裝技術(shù)。在C+環(huán)境中,要求消息被一個專門處理該類型消息的類的成員函數(shù)處理。 因此, MFC不采用case語句,而采用更加復(fù)雜和回
19、旋的。但它用私有類處理消息,而只需做下面三件事情: 從將要接收消息的CWnd類對象派生類(對于命令消息是CCmdTarget)。 在派生類中寫一個處理消息的成員函數(shù)。 在類中定義一個查找表(叫做消息映像),該表具有成員函數(shù)的條目和它要處理的消息的標識符。然后,MFC依次調(diào)用下面的函數(shù),指引輸入消息到處理函數(shù)。1) AfxWndProc( )接收消息,尋找消息所屬的CWnd對象,然后調(diào)用AfxCallWndProc( )。2) AfxCallWndProc( ) 消息(消息標識符和參數(shù))供未來參考,然后調(diào)用WindowProc( )。3) WindowProc( ) 發(fā)送消息給 OnWndMsg
20、( ) ,然后,如果消息未被處理,則發(fā)送給DefWindowproc( )。4) OnWndMsg( )要么為WM_D消息調(diào)用Ond( ),要么為WM_NOTIFY 消息調(diào)用OnNotify( )。任何被遺漏的消息是一個窗口消息。 OnWndMsg( )搜索類的消息映像,以找到一個能處理任何窗口消息的處理函數(shù)。如果 OnWndMsg()不能找到這樣的處理函數(shù),則把消息返回到WindowProc( ),由它將消息發(fā)送給DefWindowProc( )。5) Ond( ) 查看這是不是一個控件通知 ( l P a r a m不是 N U L L );如果它是, Ond( )就試圖將消息到通知的控件
21、;如果它不是一個控件通知,或者控件拒絕的消息, Ond( )就調(diào)用OnCmdMsg( )。6) OnNotify( )也試圖將消息到通知的控件;如果 不 , OnNotify( ) 就調(diào)用相同的OnCmdMsg( )函數(shù)。7) 根據(jù)接收消息的類, OnCmdMsg( )將在一個稱為命令傳遞(d Routing)的過程中潛在地傳遞命令消息和控件通知。例如,如果擁有該窗口的類是一個框架類,則命令和通知 消息也被傳遞到視圖和文檔類,并為該類尋找一個消息處理函數(shù)。為什么要消息映像?為什么要消息映像?這畢竟是C+語言;為什么OnWndMsg( )不為每個窗口消息調(diào)用一個預(yù)定義的虛擬函數(shù)?因為它太占CPU
22、。若是那樣,當掃描一個消息映像以 該過程時,OnWndMsg( )可能會做出意想不到的事情,并陷入?yún)R編器。注意通過重載WindowProc( ) 、OnWndMsg( ) 、Ond( ) 、OnNotify( ) 或OnCmdMsg( )可以修改這一過程。重載OnWndMsg( )可以在窗口消息被排序之前 該過程。重載Ond( )或OnNotify( )可以在消息被反射之前 該過程。消息和命令傳遞將在下面部分進行詳細討論。現(xiàn)在,一步一步地跟蹤窗口進程接收和解釋一個消息。1. AfxWndProc( )所有MFC窗口的窗口進程是:LRESULT AfxWndProc(HWND hWnd, UIN
23、T nMsg, WPARAM wParam, LPARAM lParam);如果一個消息被發(fā)送,則SendMessage( ) 本質(zhì)上直接調(diào)用AfxWndProc( );如果一個消息被寄送,則消息泵通過DispatchMessage( )調(diào)用AfxWndProc( )。AfxWndProc( )要做的第一件事是找到目標窗口的 CWnd對象。雖然一個窗口不知道它的CWnd對象的任何情況,但應(yīng)用程序在映像中跟蹤窗口和類的配對。一旦CWnd對象被找到, AfxCallWndProc( )就會被調(diào)用。2. AfxCallWndProc( ) AfxCallWndProc( )的原型是:LRESULT
24、AfxCallWndProc(CWnd *pWnd, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);AfxCallWndProc( ) 保存消息為將來 。事實上,即使以后改變消息中的參數(shù),當窗口進程用Default( )成員函數(shù)進行默認處理時,窗口進程也將 保 這里的參數(shù);一旦消息保存,WindowProc( )就被調(diào)用。3. WindowProc( ) WindowProc( )的原型函數(shù)為:LRESULT WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam);WindowProc(
25、)接著調(diào)用OnWndMsg( ),它試圖在類中為該消息尋找一個處理函數(shù);任何返回到WindowProc( )的未被處理的消息都被傳輸?shù)?DefWindowProc( );DefWindowProc( )是被處理的消息的貯藏所。如果沒有消息處理函數(shù),并不意味著該消息不重要,例如, 幾乎不需處理WM_PAINT消息,但它是重要的,因為DefWindowProc( ) 用該消息來繪制窗口的非客戶區(qū)。注意 MFC的CControlBar類(工具欄、 條和狀態(tài)欄的基類)重載WindowProc( ),如果任何一個下面所列的消息 處理就傳給了 條,它們將被發(fā)送回它的父類(通常是主框架類)。WM_NOTIF
26、YWM_DWM_DRAWITEMWM_MEASUREITEM WM_DELETEITEMWM_COMPAREITEMWM_VKEYTOITEMWM_CHARTOITEM也可以在父窗口中自動地處理工具欄、狀態(tài)欄或條的按鈕。但是,應(yīng)該盡可這些功能封裝到工具欄、狀態(tài)欄或條類中。CMainFrame( )類具有非常集成特性。4. OnWndMsg( )OnWndMsg( )的原型函數(shù)為:BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pResult);當消息為WM_D時,OnWndMsg( )調(diào)用Ond( );當消息
27、是WM_NOTIFY 時,則On WndMsg( )調(diào)用OnNotify( )。所有其他消息都被認為是窗口消息,并且OnWndMsg( ) 搜索類中的消息映像以找到一個處理函數(shù)。消息映像OnWndMsg( ) 通過搜索類和派生類中的消息映像為窗口消息尋找一個消息處理函數(shù)。消息映像是數(shù)據(jù)靜態(tài)表,包含類中每個消息處理函數(shù)的一個條目。每個 CWnd的派生類可以有一個消息映像(見圖3-3)。CWnd2對象兩個類從CWnd 派生 CWnd1派生于CWnd,Cnd2派生于CWnd1。每個派生類都有它的消息映像當消息進入CWnd 中時,首先在最頂層派生類的消息映像中尋找一個處理函數(shù) CWnd1對象 CWnd
28、對象 如果CWnd在該消息映像中不能找到一個消息處理函數(shù),則在下一個派生CWnd的類中尋找如果CWnd找到一個消息處理函數(shù), 則用該消息調(diào)用它圖3-3 OnWndMsg( )搜索消息映像為窗口消息定位消息處理函數(shù)每個消息映像都被括在兩個宏之間BEGIN_MESSAGE_MAP(C ,CYyy): : :Message Map entries: : : END_MESSAGE_MAPC 是該類的派生類名, CYyy是OnWndMsg( )要搜索的下一個派生類名,通常 C 派生于CYyy;在下一個類中的BEGIN_MESSAGE_MAP宏標識派生它的類,以此類推,直到所 有類中的消息映像都被搜索為
29、止。除了為 OnWndMsg( ) 標識消息映像的位置外,可以忽略這些宏是怎樣工作的。每個消息映像條目使用下面的結(jié)構(gòu):struct AFX_MSGMAP_ENTRYUINT nMessage;UINT nCode;UINT nID;UINT nLastID;UINT nSig;AFX_PMSG pfn; UNINT nMessage標識特定的WM_消息。 UNINT nCode是控件 碼,對于窗口消息該值為 0。 在下文中看到,處理命令消息和控件通知的函數(shù)使用與此相同的消息映像。 UINT nID是命令I(lǐng)D,對于窗口消息該值為0。 UINT nLastID是以nID開始 令I(lǐng)D范圍內(nèi)的最后一個
30、命令 ID,對于窗口消息該值為0。處理命令消息的函數(shù)能夠處理某一范圍的 ID。 UINT nSig定義消息處理函數(shù)的調(diào)用變量。在 AFXMSG_.H中,為nSig預(yù)定義了60多個值,例如, nSig值為iww,則在調(diào)用消息處理函數(shù)前,使 OnWndMsg( ) 格式化wParam 和lParam為兩個UINT變量,返回值為整型。 AFX_PMSG pfn是消息處理函數(shù)的地址。因此,當OnWndMsg( ) 得到一個窗口消息時,在它的派生類中尋找第一個消息映像。然后, OnWndMsg( ) 掃描那里的條目進行 n Message匹配,如果找到,它就格式化 w Param和lParam為nSig
31、指定的調(diào)用變量,并調(diào)用pfn指定的函數(shù)。如果沒有在第一個消息映像中找到一個條目,它將檢查 BEGIN_MESSAGE_MAP宏找出下一個要掃描的消息映像,以此類推,直到檢查完一個對象中的所有消息映像為止。如果OnWndMsg( ) 掃描一個對象中的所有消息映像后,沒有發(fā)現(xiàn)消息處理函數(shù),則窗口消息返回給WindowProc( ),接著由它將消息發(fā)送給DefWindowProc( )。消息映像宏AFXMSG_.H不僅包含nSig的預(yù)定義值,還包含一些有助于簡化創(chuàng)建消息映像條目的宏。 這些宏以兩種格式出現(xiàn): ON_MESSAGE宏用來處理任何WM_消息。 一個以O(shè)N_WM_ 形式出現(xiàn)的窗口消息宏,這
32、里的 WM_ 是任何當前定義的窗口消息。通常,應(yīng)該用Class Wizard自動地將這些宏添加到類的消息映像中 (見例59)。但是,不是所有這些宏都可以被自動添加,這時,可以通過參考附錄 B中宏的詳細列表,手工添加這些宏。5. Ond( )下面,繼續(xù)討論WM_D消息,上面我們已經(jīng)看到,它們被發(fā)送到Ond( )進行處理。LRESULT Ond(WPARAM wParam, LPARAM lParam);此時,一個 W M _D 消息既可以是命令消息,也可以是一個控件通知。Ond( )查看lParam是不是一個有效的窗口句柄,如果是,則 Ond( ) 以控件通知處理該消息,這里lParam是控件的
33、句柄,并且將消息反射到發(fā)送它的窗口。消息反射前面已提及,當控件狀態(tài)發(fā)生變化時,控件通知被發(fā)送到父窗口。因此,控件通知提供 給父窗口有限的能力,用來定制和補充控件工作的方式。例如,當一個組合框下拉時,父窗 口通過修改下拉列表內(nèi)容作出反應(yīng)。,把這項功能交給父窗口違背了面向?qū)ο缶幊痰囊鈭D,因為它要求每個對象都應(yīng)該所有屬于它 的功能。在上面的例子中,每次組合框移到一個新的父窗口中,則下拉功能也要移到新的父窗口。因此,將控件通知處理功能交給控件會更可取。因為每個控件已 經(jīng)有一個可以通過重載添加其他功能的 MFC類,所以若能按照那列表來處理控件通知的話將會是非常 。這樣,每當把控件移到一個新的父窗口時,不
34、必考慮必須把哪些代碼拷貝到新的父窗口。MFC用一個叫做“消息 ”的過程來支持該項功能。無論什么時候,當MFC窗口剛剛接收到一個控件通知時,它知道該通知有一個控件窗口 在某處,并且很可能有一個 MFC派生類在它,因此, MFC窗口試圖將那通知回到MFC派生類,并給它處理該通知的機會 (見圖3-4)。用這種可以將任何一個控件的所有功能放到一個井然有序的類。 CMyButton 可能有一個該消息的處理函數(shù),若沒有,則CMyDialog使它返回如果CMyDialog也不接收窗 該通知,則最后由口進程處理它創(chuàng)建一個CMyButton類和一個CMyDialog類, 以及它們的窗口對象, 使按鈕控件成為該對
35、 話的一個子窗口。CMyButton類對象按鈕窗口進程CMyDialog類對象窗口進程CMyDialog 用子截獲該消息,查看它是否是控件通知。 若是,則把它提供給該窗口的MFC類,即CMyButton按鈕窗口進程發(fā)送控 件通知到它的父窗口, 如BN_CLICKED圖3-4 消息提供了使控件通知返回到控件窗口的功能如果控件不想該消息返回, Ond( ) 如處理通用消息一樣處理該消息,并調(diào)用OnCmdMsg( )。6. OnNotify( )WM_NOTIFY消息被發(fā)送到OnNotify( )函數(shù)。BOOL OnNotify(WPARAM wParam , LPARAM lParam, LRES
36、ULT &lResult);任何發(fā)送到這里的消息都自動地被認為是一個控件通知,并且消息被反射。如果控件類 不想該消息返回,則OnNotify( )調(diào)用OnCmdMsg( )。Ond( ) 和OnNotify( ) 都調(diào)用ReflectLastMsg( ),以提供一個控件通知返回到它的控件窗口。 ReflectLastMsg( ) 獲取控件窗口的窗口句柄,并在它的消息映像中尋找WM_D+WM_REFLECT_BASE或WM_NOTIFY+WM_REFLECT_BASE和 碼。消息映像宏有三組預(yù)定義的宏(每種控件通知格式對應(yīng)一組),在控件窗口消息映像中,可以用它來處理它所反射的消息: ON_WM_
37、REFLECT( )用于第一控件通知格式。 ON_CONTROL_REFLECT( )用于第二控件通知格式。 ON_NOTIFY_REFLECT( )用于第三控件通知格式。請參考附錄B,以獲得有關(guān)的詳細列表。7. OnCmdMsg( )如果一個控件通知被它的控件窗口拒絕,則 Ond( )和OnNotify( )通過調(diào)用下面的函數(shù),像處理命令消息一樣處理它:BOOL OnCmdMsg(UINT nID, int nCode ,void*pExtra, AFX_CMDHANDLERINFO * pHandlerInfo);這里: UINT nID是命令 ID。 Int nCode是碼。對于一個命令
38、消息,該變量將賦值為CN_D(相當于0)。 Void *pExtra取決于正被處理的消息的類型:消 息 類 型Pextra包含的內(nèi)容WM_NOTIFY控件通知指向NMHDR的AFX_NOTIFY結(jié)構(gòu)的指針菜單項和工具欄更新(啟用、禁用等)指向CCmdUI派生類的指針(后面將討論)任何其他類型NULL 當Ond( ) 或OnNotify( ) 調(diào)用OnCmdMsg( ) 時, AFX_CMDHANDLERINFO*pHandlerInfo總是為NULL;當該變量不包含一個AFX_CMDHANDLERINFO結(jié)構(gòu)指針 時,OnCmdMsg( )不執(zhí)行任何它所找到 令消息處理函數(shù)。相反, OnCmd
39、Msg( )只是返回它本應(yīng)執(zhí)行的處理函數(shù)的地址。struct AFX_CMDHANDLERINFOCCmdTarget* pTarget;/ the object the function resides invoid (AFX_MSG_CALL CCmdTarget:*pmf)(void);/ the function address;當啟用或禁用菜單項和工具欄按鈕時,將使用該附加功能, 在下文中討論。接著, 在一個稱為命令傳遞的過程中,命令消息和控件通知被提供給一些類。命令傳遞OnCmdMsg( ) 實際上是CCmdTarget的成員函數(shù),而不是CWnd的成員函數(shù)。認識這一點很重要,因為它
40、 任何從 CCmdTarget派生的類接收一個命令消息,即使那些沒有一個窗口的類也可以。例如,文檔類沒有相關(guān)聯(lián)的窗口,它依賴視圖類顯示它的文檔。但是一個文檔 類是處理一個裝載或保存命令的最 地方,因此,雖然一個文檔類不能處理類似于W M _ C R E AT E或 W M _ D E S T R O Y令 消 息。 但 OnCmdMsg( )它 處 理 類 似于WM_D和WM_NOTIFY令消息。CWnd本身是從CCmdTarget派生而來的,因此, 它也能支持命令消息,如圖3-5所示。在所有的主應(yīng)用程序類(應(yīng)用程序、框架、視圖和文檔類)中,MFC通過重載OnCmdMsg( ) 執(zhí)行命令傳遞。
41、例如,視圖類重載 OnCmdMsg( ) ,使它能為文檔類提供命令和控件通知消息;文檔類重載OnCmdMsg( ),使它能為文檔模板類提供命令消息。下面的列表顯示了命令和控件通知怎樣被傳遞到應(yīng)用程序的主類:框架消息映視圖消息映文檔消息映像像像在查看它的消息映像以前,框架類中的OnCmdMsg( ) 首先調(diào)用視圖類的OnCmdMsg( )在初始的ID_FILE_SAVE消息被框架窗口接收以后, 該消息使用OnCmdMSg( )重載函數(shù)在類間傳輸框架類中的OnCmdMsg()重載函數(shù)視圖類中的OnCmdMsg()重載函數(shù)文檔類中的OnCmdMsg()重載函數(shù)視圖類中的OnCmdMsg()函 文檔類
42、中的OnCmdMsg( )數(shù)檢查它的消息映像,如果檢查消息映像,如果找到CWnd窗口 沒找到任何東西,則調(diào)用文OnSaveFile( ),則調(diào)用它進程檔類中的OnCmdMsg( )圖3-5 CCmdTarget支持沒有窗口的MFC對象的消息映像OnCmdMsg( )命令傳遞主菜單發(fā)送ID_ FILE_SAVE消息到框架窗口進程發(fā)送到MFC類 令消息按下面的順序傳遞到所列類中CFrameWnd擁有輸入焦點的所有Cview的派生類它自身的消息映像所有CwinApp的派生類CMDIFrameWnd擁有輸入焦點的所有CMDICHildWnd的派生類擁有輸入焦點的所有Cview的派生類它自身的消息映像所
43、有CwinApp的派生類CMDIChildWnd它自身的消息映像CView它自身的消息映像所有CDocument的派生類CDocument它自身的消息映像所有CDocumentTemplate的派生類CDialog它自身的消息映像它的父類的消息映像它的線程的消息映像CPropertySheet它自身的消息映像 它的父類的消息映像它的線程的消息映像傳遞效果具有累積性。被發(fā)送到 CMDIFrame Wnd 令消息,首先被提供給有效的CMDIFrameWnd中的消息映像,接著給有效的 CView、有效CView的CDocument、那個文檔的CDocTemplate、CMDIFrameWnd自身的消
44、息映像,最后給CWinApp。一旦OnCmdMsg( ) 找到一個消息處理函數(shù),命令傳遞就停止。在前面的例子中,如果OnCmdMsg( ) 在CDocument中找到一個處理函數(shù),它將用命令消息調(diào)用該處理函數(shù)并返回結(jié)果,而不用繼續(xù)傳遞給CDocTemplate。消息映像宏雖然命令消息和控件通知被傳遞的 是相同的,但是它們預(yù)定義的消息映像宏卻是不同令消息采用的形式為:ON_D( )而控件通知采用的形式為: ON_CONTROL( )為WM_D通知ON_NOTIFY( )為WM_NOTIFY通知參見附錄B的詳細列表。參見圖3-6。 AfxWndProc( )找到擁有該窗口的類對象,并調(diào)用AfxWn
45、dCallProc( ) OnWndMsg()發(fā)送WM_COM- MAND消息到OnNotify(),發(fā) 送WM_NOTIFY到OnNotify( ), 而為剩下的消息在找到的類的消息映像中尋找一個處理函數(shù) WindowProc( )調(diào)用OnWndMsg( )根據(jù)類的類型, O n CmdMsg()可能調(diào)用其他類中OnCmdMsg()重載函數(shù)。否則,在該類的消息映像中搜索一個處理函數(shù) 發(fā)送到MFC AfxWndCallproc( )保 任何未被OnWnd Msg()處 Ond( ) 和OnNotify()把控件通創(chuàng)建的窗口中的消息都被AfxWndProc( ) 處理存消息后調(diào)用找到的類的Win
46、dowProc( ), 從現(xiàn)在起,所有被調(diào)用的函數(shù)都可以被重載理的消息被發(fā)送到DefWindowProc( )知反射回到類(未顯示出來)。任何未被反射的消息被發(fā)送到OnCmdMsg( )通過完成所有這些過程,消息可以在類中被處理, 控件以被反射回到它們的控件,而命令消息可以被傳遞到應(yīng)用程序的任何地方圖3-6 描述MFC如何處理接受的3.7 處理用戶界面的對象剛剛討論過的一些成員函數(shù)也被 M F C用來更新用戶界面的狀態(tài)。具體地講, M F C用OnCmdMsg( )來啟用、禁用或檢查一個菜單中的所有菜單項和條中的所有控件 (工具欄、條和狀態(tài)欄)。無論何時打開一個菜單項, MFC更新菜單項的狀態(tài)
47、;每當應(yīng)用程序空閑時,它就更新條中控件的狀態(tài)。對于任一, M F C 進入一個循環(huán),在該循環(huán)中為每個菜單項或條控件調(diào)用OnCmdMsg( ),最多可達兩次。第一次調(diào)用OnCmdMsg( )時,應(yīng)用程序可以啟用或禁用菜單項或控件;如果不能為請求的行為提供一個特定的用戶界面處理函數(shù),則 OnCmdMsg( )被第二次調(diào)用,以檢查菜單項或控件究竟有沒有一個消息處理函數(shù),如果沒有, OnCmdMsg( ) 將自動禁用菜單項或控件。注意如果想關(guān)閉這一自動禁用特性,可以將CMainFrame類中的m_bAutoEnable設(shè)為FALSE。但是,這對工具欄不起作用。當OnCmdMsg( )被調(diào)用,并應(yīng)用程序
48、更新界面時,它被賦予如下參數(shù):OnCmdMsg(nID, CN_UPDATE_D_UI, CCmdUI *pCmdUI, NULL); nID是需要更新的菜單項或條控件的控件 ID。 *pCmdUI指向一個類,該類包含應(yīng)用程序更新菜單項和控件的成員函數(shù)。接著,按命令消息中相同的次序, OnCmdMsg( ) 仔細查看相同的消息映像,直到發(fā)現(xiàn)一個特定的用戶界面消息處理函數(shù)。處理CN_UPDATE_D_UI的預(yù)定義的宏是:ON_UPDATE_D_UI(id, Handler);對于某一范圍內(nèi)的控件ID,預(yù)定義的宏是:ON_UPDATE_D_UI_RANGE(id, idLast, Handler)
49、;對于每個宏,處理函數(shù)有相同的格式:void Handler(CCmdUI *pCmdUI)pCmdUI-Enable(pFlag);CCmdUI對象包含如下重要的成員變量和函數(shù): m_nID是控件ID,當某個范圍的控件ID可以用相同的處理函數(shù)更新時,它對第二宏格 式是有用的。 Enable (BOOL bOn),如果bOn設(shè)為FALSE,將使菜單項或控件無效。 SetCheck (int nCheck),如果nCheck為1,則將檢查菜單項。 SetRadio (BOOL bOn),更新單選按鈕。 SetText (LPCTSTR string),設(shè)置控件或菜單項的文本。這些成員函數(shù)中的每一
50、個都被重載,以便當菜單被更新時,調(diào)用禁用菜單項的代碼,當 一個 條被更新時,調(diào)用禁用控件的代碼。當OnCmdMsg( ) 被第二次調(diào)用來確定應(yīng)用程序是否有一個菜單項或控件的處理函數(shù)時, 它被賦予如下變量:BOOL bHandler=OnCmdMsg(nID, CN_D, CCmdUI *pCmdUI, AFX_CMDHANDLERINFO *info);在第一次看到OnCmdMsg( ) 的變量時已提及,一個 AFX_CMDHANDLERINFO結(jié)構(gòu)的指針,使OnCmdMsg( ) 只查找一個消息處理函數(shù)而不執(zhí)行。如果返回值為 FALSE,則沒有處理函數(shù),菜單項和控件被禁用。關(guān)于用CCmdUI
51、類對象更新用戶界面的例子,參見例 16、例17、例18。3.8 創(chuàng)建自定義窗口消息從WM_NULL到WM_USER有70個系統(tǒng)定義的窗口消息。根據(jù) 的意愿,用戶可以創(chuàng)建兩種自定義的窗口消息:靜態(tài)定義的大于 WM_USER值的窗口消息,在給定字符串標識符時 動態(tài)定義的窗口消息。注意 請記住,窗口消息主要是為窗口內(nèi)在運行機制設(shè)計的,而不是為處理用戶命令設(shè)計的。如果只想告訴應(yīng)用程序的一部分或別的應(yīng)用程序處理一個用戶命令,那么用已定義的WM_D窗口消息和一個新令I(lǐng)D。3.8.1 靜態(tài)分配的窗口消息Windows保留了0和WM_USER-1之間的整數(shù)范圍,作為系統(tǒng)定義的窗口消息;還有一個從WM_USER
52、一直到OX7fff的整數(shù)范圍,留給自定義消息用。可以用一個簡單的 #define語句定義消息:#define WM_MYMESSAGE1 WM_USER #define WM_MYMESSAGE2 WM_USER+1: : :然后,可以像處理任何其他窗口消息一樣,發(fā)送或寄送這些消息。SendMessage(WM_MYMESSAGE1, wParam, lParam)或PostMessage(WM_MYMESSAGE1, wParam, lParam).可以用下面的宏在消息映像中獲取這些新消息:ON_MESSAGE(WM_MYMESSAGE1, Handler)在這里,處理函數(shù)將具有如下格式:L
53、RESULT Handler(WPARAM, LPARAM)通過修改下面的宏,可以定義完全屬于用戶的消息映像宏。#define ON_MY_MESSAGE1() WM_MYMESSAGE1, 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(AFX_PMSGW) (LRESULT (AFX_MSG_CALL CWnd:*)(WPARAM, PARAM)&OnMyMessage1,在這里,自動賦予處理函數(shù)名為 OnMessage1,但還是具有相同的調(diào)用變量。為了改變調(diào)用變量,在AfXMSG_.H文件中尋找一個更加合適的nSig值,并替換AfxSig_lwl,然后修改宏 中的最后一行
54、,以 新變量。有關(guān)例子參見例 62。3.8.2 動態(tài)分配的窗口消息為了在應(yīng)用程序間發(fā)送消息,應(yīng)該用下面的語句創(chuàng)建一個基于描述性字符串的新的窗口 消息。UINT wm_MyMessage1=:RegisterWindowMessage(LPCSTR Identifier); Identifier是描述性字符串。 wm_MyMessage1是在0xc000和0xffff之間的一個動態(tài)分配的窗口消息。為了處理在消息映像中的消息,可以用: ON_REGISTERED_MESSAGE(wm_MyMessage1,Handler)把由RegisterWindowMessage( )分配的值傳送給它。該消息的處理函數(shù)看起來像:LRESULT Handler(WPARAM, LPARAM)一個動態(tài)分配的窗口消息使得應(yīng)用程序間窗口消息的維
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024項目管理考試輔導(dǎo)材料試題及答案
- 廣告策劃中的危機公關(guān)處理考核試卷
- 財務(wù)數(shù)據(jù)解讀與應(yīng)用試題及答案
- 陜西排水帶施工方案
- 針對新形勢的注冊會計師考試變革探討試題及答案
- 2024項目管理專業(yè)知識考題試題及答案
- 2024年項目成功的關(guān)鍵因素與應(yīng)對方案試題及答案
- 打井前施工方案怎么寫
- 項目管理專業(yè)人士資格考試的備考經(jīng)驗試題及答案
- 電視機語音助手與智能交互技術(shù)考核試卷
- 2025年中考語文一輪專題復(fù)習:古詩詞曲梳理復(fù)習重點整合
- 2025年中學(xué)教師資格考試《綜合素質(zhì)》教育教學(xué)能力提升教育政策分析試題(含答案)
- 2025-2030中國氯堿行業(yè)市場發(fā)展分析及發(fā)展趨勢預(yù)測研究報告
- 2025-2030中國建筑智能化工程行業(yè)市場發(fā)展分析及發(fā)展趨勢前景研究報告
- 呵護地球家園點亮綠色希望-2025年4月22日第56個世界地球日主題教育班會 高中主題班會優(yōu) 質(zhì)課件
- 網(wǎng)絡(luò)安全問題及其防范措施(基礎(chǔ)篇)-國家計算機網(wǎng)絡(luò)應(yīng)急中心
- 橋隧工技能鑒定理論資源高級技師模擬考試題含答案
- 2025-2030中國5G基站建設(shè)情況及前景趨勢與投資研究報告
- 話題10 AI人工智能-2025年中考《英語》高頻熱點話題寫作通關(guān)攻略
- 2024年上海市工業(yè)技術(shù)學(xué)校招聘筆試真題
- 2025年中國智能可穿戴設(shè)備市場深度調(diào)研分析及投資前景研究預(yù)測報告
評論
0/150
提交評論