版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、第3章 消 息 處 理第1章討論了MFC用戶界面的基本要素:窗口、窗口類和 CWnd;第2章討論了 MFC 庫(kù)的其他類,尤其是那些 MFC應(yīng)用程序內(nèi)核的類。在本章中, 討論 MFC類和它們的窗口怎樣進(jìn)行互相通信的。我們發(fā)現(xiàn)有三種類型的消息:窗口、命令 (d)和控件通知(Control Notification),并且這些消息既可以發(fā)送 (sent),也可以寄送(post);接著,將跟蹤一個(gè)被MFC窗口進(jìn)程處理的消息;最后,將討論重定向消息的 。3.1 發(fā)送或寄送一個(gè)消息第1章已提及,每個(gè)窗口使用窗口進(jìn)程處理發(fā)送給它的消息。消息可以來(lái)自系統(tǒng)、你的應(yīng) 用程序或別的應(yīng)用程序。消息告訴窗口進(jìn)程執(zhí)行某個(gè)
2、任務(wù) (如初始化 、繪制或銷毀一個(gè)窗口等),或者通知它發(fā)生某個(gè) (如鼠標(biāo)正單擊窗口)。系統(tǒng)或應(yīng)用程序有兩種傳輸消息的 :發(fā)送消息或寄送消息。3.1.1 發(fā)送一個(gè)消息發(fā)送一個(gè)消息時(shí),直接調(diào)用窗口的窗口進(jìn)程。通信是即時(shí)的,直到窗口進(jìn)程為調(diào)用函數(shù) 返回一個(gè)結(jié)果后,應(yīng)用程序才能繼續(xù)。3.1.2 寄送一個(gè)消息窗口對(duì)象寄送一個(gè)消息時(shí),把消息發(fā)送到擁有那個(gè)窗口的應(yīng)用程序消息隊(duì)列中。一有空閑,應(yīng)用 程序就搜索消息隊(duì)列,并在消息隊(duì)列中處理消息,即從隊(duì)列中刪除它們,并將它們發(fā)送到即 定窗口。通信將可能延遲,直到目標(biāo)應(yīng)用程序獲得處理消息的時(shí)間。調(diào)用函數(shù)發(fā)送消息后即 返回,但結(jié)果只是表示消息寄送 與否,而不是被調(diào)用窗
3、口進(jìn)程的結(jié)果 (見(jiàn)圖3-1)。被發(fā)送的消息直接調(diào)用該窗口的窗口進(jìn)程被寄送的消息延遲在消息泵消息n+1 消息n+2 消息n+3 消息n+4WndProc地址當(dāng)應(yīng)用程序空閑時(shí), 抽出寄送到隊(duì)列中 的消息并調(diào)用該窗 口的窗口進(jìn)程應(yīng)用程序消息隊(duì)列中消息隊(duì)列圖3-1 發(fā)送消息時(shí)通信是即時(shí)的,而寄送消息時(shí)通信可能延遲3.1.3 發(fā)送一個(gè)消息與寄送一個(gè)消息的比較鼠標(biāo)和鍵盤(pán)消息通常是寄送的,而所有其他消息通常都是發(fā)送的。在消息隊(duì)列中,寄送第3章 消 息 處 理49的消息接受特殊的鼠標(biāo)和鍵盤(pán)處理。通常,應(yīng)該盡量發(fā)送一個(gè)消息,除非想把動(dòng)作延有鼠標(biāo)和鍵盤(pán)消息被處理之后。所3.2怎樣使用MFC發(fā)送一個(gè)消息用MFC發(fā)送
4、一個(gè)消息的是,首先,應(yīng)獲取接收消息的 CWnd類對(duì)象的指針;然后,調(diào)用CWnd的成員函數(shù)SendMessage( )。LRESULT Res=pWnd-SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);pWnd指針指向目標(biāo)CWnd類對(duì)象。變量Msg是消息, wParam和lParam變量包含消息的參數(shù),如鼠標(biāo)單擊哪里或選擇了什么菜單項(xiàng)。目標(biāo)窗口返回的消息結(jié)果放在變量 Res中。發(fā)送消息到一個(gè)沒(méi)有CWnd類對(duì)象的窗口,可以用下列目標(biāo)窗口的句柄直接調(diào)用 Windows API:LRESULT Res=:SendMessage(HWND hWnd
5、 , UINT Msg , WPARAM wParam , LPARAM lParam);這里的hWnd是目標(biāo)窗口的句柄。3.3 怎樣用MFC寄送一個(gè)消息用MFC寄送一個(gè)消息與發(fā)送一個(gè)消息幾乎相同,但寄送時(shí)用 PostMessage( ) ,而不是用SendMessage( );返回值Res也不一樣, Res不是一個(gè)由目標(biāo)窗口返回的值,而是一個(gè)布爾值, 用來(lái)表示消息是否 地放到消息隊(duì)列中。檢索一個(gè)寄送消息正常情況下,一旦消息被寄送后,應(yīng)用程序在 發(fā)送它。但是在特殊情況下,需要你去刪除一個(gè)消息,例如想在應(yīng)用程序接收到某種消息之前停止應(yīng)用程序。有兩種 可以從應(yīng)用程序消息隊(duì)列中刪除一個(gè)消息,但這兩種
6、 都沒(méi)有涉及 MFC。 第法:在不干擾任何事情之下窺視消息隊(duì)列,看看一個(gè)消息是否在那里。BOOL res=:PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); 第二種 :實(shí)際上是等待,一直等到一個(gè)新的消息到達(dá)隊(duì)列為止,然后刪除并返回 該消息。BOOL res=:GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);在這兩種 中,變量hWnd指定要截獲消息的窗口,如果該
7、變量設(shè)為 NULL,所有窗口消息將被截獲。wMsgFilterMin和wMsgFilterMax變量與SendMessage( )中的變量Msg相對(duì)應(yīng), 指定查看消息的范圍。如果用“ 0, 0 ”,則所有的消息被截獲。如果用 WM_KEYFIRST, WM_KEYLAST或WM_MOUSEFIRST, WM_MOUSELAST,則所有鍵盤(pán)或鼠標(biāo)的消息將被截獲。w R e m o v e M s g變量指定PeekMessage( )是 否應(yīng)該真正地從隊(duì)列中刪除該消息。(GetMessage( )總是刪除消息)。該變量可以取兩個(gè)值: PM_REMOVE,PeekMessage( )將刪除消息。
8、PM_NOREMOVE,PeekMessage( )將把消息留在隊(duì)列里,并返回它的一個(gè)拷貝。當(dāng)然,如果把消息留在消息隊(duì)列中,然后再次調(diào)用 PeekMessage( ) 查看相同類型的消息, 則將返回完全相同的消息。lpMsg變量是一個(gè)指向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ā)送到窗口。當(dāng)用Send Message()或Post Message()發(fā)送一個(gè)窗口消息時(shí),變量 Message、w Param和lParam的格式如下:Messagew
10、ParamlParamWM_定義令定義令WM_可以是許多窗口消息之一,如下列窗口: WM_CREATE,告訴窗口初始化。 WM_PAINT,告訴窗口繪制。 WM_MOUSEMOVE,告訴窗口鼠標(biāo)移經(jīng)它。有關(guān)某些公共窗口消息,參見(jiàn)附錄B。若需要窗口消息的完全的列表,請(qǐng)參考 MFC文檔。3.4.2 命令消息命令消息與處理用戶請(qǐng)求相關(guān),當(dāng)用戶單擊一個(gè)菜單項(xiàng)或工具欄時(shí),命令消息產(chǎn)生, 并被發(fā)送到能處理該請(qǐng)求的類對(duì)象(如,裝載文件、編輯文本和保存選項(xiàng)等)。當(dāng)用SendMessage( )或PostMessage( )發(fā)送窗口消息時(shí),變量Message、wParam和lParam的格式如下:Message
11、wParamlParamWM_D0d ID0d ID要么是選中菜單項(xiàng)的ID,要么是被單擊的工具欄按鈕。注意d ID不能大于一個(gè)字長(zhǎng),如果使它大于一個(gè)字長(zhǎng),系統(tǒng)就只用 0來(lái)填充高位字。某些控件通知也用WM_D消息,區(qū)別兩種消息的唯一是lParam是否為NULL。3.4.3 控件通知通常,控件通知在某些重要發(fā)生時(shí),由控件窗口發(fā)送到父窗口,如打開(kāi)一個(gè)組合框。控件通知為父窗口進(jìn)一步子窗口提供了機(jī)會(huì)。例如,打開(kāi)一個(gè)組合框時(shí),父窗口可以用 組合框初建時(shí)得不到的消息填充它。控件通知經(jīng)歷了一個(gè)演變過(guò)程,因而 SendMessage( )的變量Message、wParam和lParam有三種格式。1. 第一控件
12、通知格式第一控件通知格式只是窗口消息的子集。MessagewParamlParamWM_定義令定義令WM_可以是下面消息中的任何一種: WM_PARENTNOTIFY表示一個(gè)控件窗口要么已被建立或銷毀,要么鼠標(biāo)已單擊了該 窗口。 WM_CTLCOLOR、WM_DRAWITEM、WM_MEASUREITEM、WM_DELETEITEM、WM_CHARTOITEM、WM_VKEYTOITEM或WM_COMPAREITEM都是送往父窗口的 消息,用來(lái)繪制自身的控件窗口。 WM_HSCROLL或WM_VSCROLL由滾動(dòng)條控件發(fā)送,通知父窗口滾動(dòng)窗口。2. 第二控件通知格式第二控件通知格式使用WM_D
13、消息,與命令消息共享。MessagewParamlParamWM_ DXN_ 控件ID窗口句柄lParam變量用來(lái)區(qū)分是命令消息還是控件通知??丶ㄖ?lParam中有一個(gè)有定義的句柄,用來(lái)標(biāo)識(shí)發(fā)出通知的控件;而命令消息中 lParam為NULL。XN_值因發(fā)出通知的控件不同而不同,例如, XN_值為EN_CHANGE,告訴父窗口顯示在編輯框控件中的文本已發(fā)生變化。還有其他一些例子列在附錄 B中。3. 第三控件通知格式第三控件通知格式也是最靈活 格式,它用 WM_NOTIFY消息。MessagewParamlParamWM_NOTIFY控件ID指向NMHDR的指針lParam值指向一個(gè)結(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)。為什么要這個(gè)頭?因?yàn)槟承┛丶肗MHDR作為頭發(fā)送一個(gè)更大結(jié)構(gòu)的消息,即使那些不知道更大結(jié)構(gòu)內(nèi)容的函數(shù)還是能處理通知頭。3.5 MFC怎樣接收一個(gè)寄送的消息MFC處理一個(gè)寄送和發(fā)送消息的唯一明顯不同是寄送的消息要在應(yīng)用程序的消息隊(duì)列中 花費(fèi)一些時(shí)間。在消息泵(message pump)彈出它之前,它要一直在隊(duì)列中。消息泵MFC應(yīng)用程序中的消息泵在CWinApp的成員函數(shù)Run( ) 中。應(yīng)用程序開(kāi)始運(yùn)行時(shí), Run( ) 就被調(diào)用, Run( ) 把時(shí)間分割成兩部分。一部分用來(lái)執(zhí)行 處理,如取消臨時(shí) CWnd對(duì)象; 另一部分用來(lái)
16、檢查消息隊(duì)列。當(dāng)一個(gè)新的消息進(jìn)來(lái)時(shí), Run( )抽取它 即用GetMessage( )從隊(duì)列中取出該消息,運(yùn)行兩個(gè)消息翻譯函數(shù),然后用 DispatchMessage( ) 函數(shù)調(diào)用該消息預(yù)期的目標(biāo)窗口進(jìn)程(見(jiàn)圖3-2)。空閑處理 (內(nèi)務(wù)處理、處理)新的消息出現(xiàn)在消息隊(duì)列中?翻譯字符消息發(fā)送消息到窗口進(jìn)程圖3-2 消息泵執(zhí)行處理并檢查消息隊(duì)列消息泵調(diào)用的兩個(gè)翻譯函數(shù)是PreTranslateMessage( )和:TranslateMessage( )。目標(biāo)窗口的MFC類可調(diào)用PreTranslateMessage在發(fā)送消息給它之前進(jìn)行消息翻譯,例如, CFrameWnd用PreTransl
17、ateMessage( ) 將 鍵(如,Ctrl+S 文件)轉(zhuǎn)換為命令消息。翻譯前的消息通常被處理掉,而翻譯后的消息(如果有的話)將被重新寄送到隊(duì)列里。:TranslateMessage是一個(gè)窗口函數(shù),將原始鍵碼轉(zhuǎn)換為鍵字符。消息一旦被DispatchMessage( ) 發(fā)送, MFC處理它就像處理SendMessage( ) 發(fā)送的消息一樣。3.6 MFC怎樣處理一個(gè)接收到的消息處理接收到的消息的目的非常簡(jiǎn)單:將消息指向一個(gè)函數(shù),該函數(shù)通過(guò)消息中的消息標(biāo) 識(shí)符處理它。非MFC窗口用簡(jiǎn)單的case語(yǔ)句來(lái)實(shí)現(xiàn)該目標(biāo),每個(gè)case語(yǔ)句執(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ù)揭粋€(gè)默認(rèn)的消息處理函數(shù),但是, case語(yǔ)句不能很好地適應(yīng)C+和封裝技術(shù)。在C+環(huán)境中,要求消息被一個(gè)專門(mén)處理該類型消息的類的成員函數(shù)處理。 因此, MFC不采用case語(yǔ)句,而采用更加復(fù)雜和回
19、旋的。但它用私有類處理消息,而只需做下面三件事情: 從將要接收消息的CWnd類對(duì)象派生類(對(duì)于命令消息是CCmdTarget)。 在派生類中寫(xiě)一個(gè)處理消息的成員函數(shù)。 在類中定義一個(gè)查找表(叫做消息映像),該表具有成員函數(shù)的條目和它要處理的消息的標(biāo)識(shí)符。然后,MFC依次調(diào)用下面的函數(shù),指引輸入消息到處理函數(shù)。1) AfxWndProc( )接收消息,尋找消息所屬的CWnd對(duì)象,然后調(diào)用AfxCallWndProc( )。2) AfxCallWndProc( ) 消息(消息標(biāo)識(shí)符和參數(shù))供未來(lái)參考,然后調(diào)用WindowProc( )。3) WindowProc( ) 發(fā)送消息給 OnWndMsg
20、( ) ,然后,如果消息未被處理,則發(fā)送給DefWindowproc( )。4) OnWndMsg( )要么為WM_D消息調(diào)用Ond( ),要么為WM_NOTIFY 消息調(diào)用OnNotify( )。任何被遺漏的消息是一個(gè)窗口消息。 OnWndMsg( )搜索類的消息映像,以找到一個(gè)能處理任何窗口消息的處理函數(shù)。如果 OnWndMsg()不能找到這樣的處理函數(shù),則把消息返回到WindowProc( ),由它將消息發(fā)送給DefWindowProc( )。5) Ond( ) 查看這是不是一個(gè)控件通知 ( l P a r a m不是 N U L L );如果它是, Ond( )就試圖將消息到通知的控件
21、;如果它不是一個(gè)控件通知,或者控件拒絕的消息, Ond( )就調(diào)用OnCmdMsg( )。6) OnNotify( )也試圖將消息到通知的控件;如果 不 , OnNotify( ) 就調(diào)用相同的OnCmdMsg( )函數(shù)。7) 根據(jù)接收消息的類, OnCmdMsg( )將在一個(gè)稱為命令傳遞(d Routing)的過(guò)程中潛在地傳遞命令消息和控件通知。例如,如果擁有該窗口的類是一個(gè)框架類,則命令和通知 消息也被傳遞到視圖和文檔類,并為該類尋找一個(gè)消息處理函數(shù)。為什么要消息映像?為什么要消息映像?這畢竟是C+語(yǔ)言;為什么OnWndMsg( )不為每個(gè)窗口消息調(diào)用一個(gè)預(yù)定義的虛擬函數(shù)?因?yàn)樗糃PU
22、。若是那樣,當(dāng)掃描一個(gè)消息映像以 該過(guò)程時(shí),OnWndMsg( )可能會(huì)做出意想不到的事情,并陷入?yún)R編器。注意通過(guò)重載WindowProc( ) 、OnWndMsg( ) 、Ond( ) 、OnNotify( ) 或OnCmdMsg( )可以修改這一過(guò)程。重載OnWndMsg( )可以在窗口消息被排序之前 該過(guò)程。重載Ond( )或OnNotify( )可以在消息被反射之前 該過(guò)程。消息和命令傳遞將在下面部分進(jìn)行詳細(xì)討論?,F(xiàn)在,一步一步地跟蹤窗口進(jìn)程接收和解釋一個(gè)消息。1. AfxWndProc( )所有MFC窗口的窗口進(jìn)程是:LRESULT AfxWndProc(HWND hWnd, UIN
23、T nMsg, WPARAM wParam, LPARAM lParam);如果一個(gè)消息被發(fā)送,則SendMessage( ) 本質(zhì)上直接調(diào)用AfxWndProc( );如果一個(gè)消息被寄送,則消息泵通過(guò)DispatchMessage( )調(diào)用AfxWndProc( )。AfxWndProc( )要做的第一件事是找到目標(biāo)窗口的 CWnd對(duì)象。雖然一個(gè)窗口不知道它的CWnd對(duì)象的任何情況,但應(yīng)用程序在映像中跟蹤窗口和類的配對(duì)。一旦CWnd對(duì)象被找到, AfxCallWndProc( )就會(huì)被調(diào)用。2. AfxCallWndProc( ) AfxCallWndProc( )的原型是:LRESULT
24、AfxCallWndProc(CWnd *pWnd, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);AfxCallWndProc( ) 保存消息為將來(lái) 。事實(shí)上,即使以后改變消息中的參數(shù),當(dāng)窗口進(jìn)程用Default( )成員函數(shù)進(jìn)行默認(rèn)處理時(shí),窗口進(jìn)程也將 保 這里的參數(shù);一旦消息保存,WindowProc( )就被調(diào)用。3. WindowProc( ) WindowProc( )的原型函數(shù)為:LRESULT WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam);WindowProc(
25、)接著調(diào)用OnWndMsg( ),它試圖在類中為該消息尋找一個(gè)處理函數(shù);任何返回到WindowProc( )的未被處理的消息都被傳輸?shù)?DefWindowProc( );DefWindowProc( )是被處理的消息的貯藏所。如果沒(méi)有消息處理函數(shù),并不意味著該消息不重要,例如, 幾乎不需處理WM_PAINT消息,但它是重要的,因?yàn)镈efWindowProc( ) 用該消息來(lái)繪制窗口的非客戶區(qū)。注意 MFC的CControlBar類(工具欄、 條和狀態(tài)欄的基類)重載WindowProc( ),如果任何一個(gè)下面所列的消息 處理就傳給了 條,它們將被發(fā)送回它的父類(通常是主框架類)。WM_NOTIF
26、YWM_DWM_DRAWITEMWM_MEASUREITEM WM_DELETEITEMWM_COMPAREITEMWM_VKEYTOITEMWM_CHARTOITEM也可以在父窗口中自動(dòng)地處理工具欄、狀態(tài)欄或條的按鈕。但是,應(yīng)該盡可這些功能封裝到工具欄、狀態(tài)欄或條類中。CMainFrame( )類具有非常集成特性。4. OnWndMsg( )OnWndMsg( )的原型函數(shù)為:BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pResult);當(dāng)消息為WM_D時(shí),OnWndMsg( )調(diào)用Ond( );當(dāng)消息
27、是WM_NOTIFY 時(shí),則On WndMsg( )調(diào)用OnNotify( )。所有其他消息都被認(rèn)為是窗口消息,并且OnWndMsg( ) 搜索類中的消息映像以找到一個(gè)處理函數(shù)。消息映像OnWndMsg( ) 通過(guò)搜索類和派生類中的消息映像為窗口消息尋找一個(gè)消息處理函數(shù)。消息映像是數(shù)據(jù)靜態(tài)表,包含類中每個(gè)消息處理函數(shù)的一個(gè)條目。每個(gè) CWnd的派生類可以有一個(gè)消息映像(見(jiàn)圖3-3)。CWnd2對(duì)象兩個(gè)類從CWnd 派生 CWnd1派生于CWnd,Cnd2派生于CWnd1。每個(gè)派生類都有它的消息映像當(dāng)消息進(jìn)入CWnd 中時(shí),首先在最頂層派生類的消息映像中尋找一個(gè)處理函數(shù) CWnd1對(duì)象 CWnd
28、對(duì)象 如果CWnd在該消息映像中不能找到一個(gè)消息處理函數(shù),則在下一個(gè)派生CWnd的類中尋找如果CWnd找到一個(gè)消息處理函數(shù), 則用該消息調(diào)用它圖3-3 OnWndMsg( )搜索消息映像為窗口消息定位消息處理函數(shù)每個(gè)消息映像都被括在兩個(gè)宏之間BEGIN_MESSAGE_MAP(C ,CYyy): : :Message Map entries: : : END_MESSAGE_MAPC 是該類的派生類名, CYyy是OnWndMsg( )要搜索的下一個(gè)派生類名,通常 C 派生于CYyy;在下一個(gè)類中的BEGIN_MESSAGE_MAP宏標(biāo)識(shí)派生它的類,以此類推,直到所 有類中的消息映像都被搜索為
29、止。除了為 OnWndMsg( ) 標(biāo)識(shí)消息映像的位置外,可以忽略這些宏是怎樣工作的。每個(gè)消息映像條目使用下面的結(jié)構(gòu):struct AFX_MSGMAP_ENTRYUINT nMessage;UINT nCode;UINT nID;UINT nLastID;UINT nSig;AFX_PMSG pfn; UNINT nMessage標(biāo)識(shí)特定的WM_消息。 UNINT nCode是控件 碼,對(duì)于窗口消息該值為 0。 在下文中看到,處理命令消息和控件通知的函數(shù)使用與此相同的消息映像。 UINT nID是命令I(lǐng)D,對(duì)于窗口消息該值為0。 UINT nLastID是以nID開(kāi)始 令I(lǐng)D范圍內(nèi)的最后一個(gè)
30、命令 ID,對(duì)于窗口消息該值為0。處理命令消息的函數(shù)能夠處理某一范圍的 ID。 UINT nSig定義消息處理函數(shù)的調(diào)用變量。在 AFXMSG_.H中,為nSig預(yù)定義了60多個(gè)值,例如, nSig值為iww,則在調(diào)用消息處理函數(shù)前,使 OnWndMsg( ) 格式化wParam 和lParam為兩個(gè)UINT變量,返回值為整型。 AFX_PMSG pfn是消息處理函數(shù)的地址。因此,當(dāng)OnWndMsg( ) 得到一個(gè)窗口消息時(shí),在它的派生類中尋找第一個(gè)消息映像。然后, OnWndMsg( ) 掃描那里的條目進(jìn)行 n Message匹配,如果找到,它就格式化 w Param和lParam為nSig
31、指定的調(diào)用變量,并調(diào)用pfn指定的函數(shù)。如果沒(méi)有在第一個(gè)消息映像中找到一個(gè)條目,它將檢查 BEGIN_MESSAGE_MAP宏找出下一個(gè)要掃描的消息映像,以此類推,直到檢查完一個(gè)對(duì)象中的所有消息映像為止。如果OnWndMsg( ) 掃描一個(gè)對(duì)象中的所有消息映像后,沒(méi)有發(fā)現(xiàn)消息處理函數(shù),則窗口消息返回給WindowProc( ),接著由它將消息發(fā)送給DefWindowProc( )。消息映像宏AFXMSG_.H不僅包含nSig的預(yù)定義值,還包含一些有助于簡(jiǎn)化創(chuàng)建消息映像條目的宏。 這些宏以兩種格式出現(xiàn): ON_MESSAGE宏用來(lái)處理任何WM_消息。 一個(gè)以O(shè)N_WM_ 形式出現(xiàn)的窗口消息宏,這
32、里的 WM_ 是任何當(dāng)前定義的窗口消息。通常,應(yīng)該用Class Wizard自動(dòng)地將這些宏添加到類的消息映像中 (見(jiàn)例59)。但是,不是所有這些宏都可以被自動(dòng)添加,這時(shí),可以通過(guò)參考附錄 B中宏的詳細(xì)列表,手工添加這些宏。5. Ond( )下面,繼續(xù)討論WM_D消息,上面我們已經(jīng)看到,它們被發(fā)送到Ond( )進(jìn)行處理。LRESULT Ond(WPARAM wParam, LPARAM lParam);此時(shí),一個(gè) W M _D 消息既可以是命令消息,也可以是一個(gè)控件通知。Ond( )查看lParam是不是一個(gè)有效的窗口句柄,如果是,則 Ond( ) 以控件通知處理該消息,這里lParam是控件的
33、句柄,并且將消息反射到發(fā)送它的窗口。消息反射前面已提及,當(dāng)控件狀態(tài)發(fā)生變化時(shí),控件通知被發(fā)送到父窗口。因此,控件通知提供 給父窗口有限的能力,用來(lái)定制和補(bǔ)充控件工作的方式。例如,當(dāng)一個(gè)組合框下拉時(shí),父窗 口通過(guò)修改下拉列表內(nèi)容作出反應(yīng)。,把這項(xiàng)功能交給父窗口違背了面向?qū)ο缶幊痰囊鈭D,因?yàn)樗竺總€(gè)對(duì)象都應(yīng)該所有屬于它 的功能。在上面的例子中,每次組合框移到一個(gè)新的父窗口中,則下拉功能也要移到新的父窗口。因此,將控件通知處理功能交給控件會(huì)更可取。因?yàn)槊總€(gè)控件已 經(jīng)有一個(gè)可以通過(guò)重載添加其他功能的 MFC類,所以若能按照那列表來(lái)處理控件通知的話將會(huì)是非常 。這樣,每當(dāng)把控件移到一個(gè)新的父窗口時(shí),不
34、必考慮必須把哪些代碼拷貝到新的父窗口。MFC用一個(gè)叫做“消息 ”的過(guò)程來(lái)支持該項(xiàng)功能。無(wú)論什么時(shí)候,當(dāng)MFC窗口剛剛接收到一個(gè)控件通知時(shí),它知道該通知有一個(gè)控件窗口 在某處,并且很可能有一個(gè) MFC派生類在它,因此, MFC窗口試圖將那通知回到MFC派生類,并給它處理該通知的機(jī)會(huì) (見(jiàn)圖3-4)。用這種可以將任何一個(gè)控件的所有功能放到一個(gè)井然有序的類。 CMyButton 可能有一個(gè)該消息的處理函數(shù),若沒(méi)有,則CMyDialog使它返回如果CMyDialog也不接收窗 該通知,則最后由口進(jìn)程處理它創(chuàng)建一個(gè)CMyButton類和一個(gè)CMyDialog類, 以及它們的窗口對(duì)象, 使按鈕控件成為該對(duì)
35、 話的一個(gè)子窗口。CMyButton類對(duì)象按鈕窗口進(jìn)程CMyDialog類對(duì)象窗口進(jìn)程CMyDialog 用子截獲該消息,查看它是否是控件通知。 若是,則把它提供給該窗口的MFC類,即CMyButton按鈕窗口進(jìn)程發(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ā)送到這里的消息都自動(dòng)地被認(rèn)為是一個(gè)控件通知,并且消息被反射。如果控件類 不想該消息返回,則OnNotify( )調(diào)用OnCmdMsg( )。Ond( ) 和OnNotify( ) 都調(diào)用ReflectLastMsg( ),以提供一個(gè)控件通知返回到它的控件窗口。 ReflectLastMsg( ) 獲取控件窗口的窗口句柄,并在它的消息映像中尋找WM_D+WM_REFLECT_BASE或WM_NOTIFY+WM_REFLECT_BASE和 碼。消息映像宏有三組預(yù)定義的宏(每種控件通知格式對(duì)應(yīng)一組),在控件窗口消息映像中,可以用它來(lái)處理它所反射的消息: ON_WM_
37、REFLECT( )用于第一控件通知格式。 ON_CONTROL_REFLECT( )用于第二控件通知格式。 ON_NOTIFY_REFLECT( )用于第三控件通知格式。請(qǐng)參考附錄B,以獲得有關(guān)的詳細(xì)列表。7. OnCmdMsg( )如果一個(gè)控件通知被它的控件窗口拒絕,則 Ond( )和OnNotify( )通過(guò)調(diào)用下面的函數(shù),像處理命令消息一樣處理它:BOOL OnCmdMsg(UINT nID, int nCode ,void*pExtra, AFX_CMDHANDLERINFO * pHandlerInfo);這里: UINT nID是命令 ID。 Int nCode是碼。對(duì)于一個(gè)命令
38、消息,該變量將賦值為CN_D(相當(dāng)于0)。 Void *pExtra取決于正被處理的消息的類型:消 息 類 型Pextra包含的內(nèi)容WM_NOTIFY控件通知指向NMHDR的AFX_NOTIFY結(jié)構(gòu)的指針菜單項(xiàng)和工具欄更新(啟用、禁用等)指向CCmdUI派生類的指針(后面將討論)任何其他類型NULL 當(dāng)Ond( ) 或OnNotify( ) 調(diào)用OnCmdMsg( ) 時(shí), AFX_CMDHANDLERINFO*pHandlerInfo總是為NULL;當(dāng)該變量不包含一個(gè)AFX_CMDHANDLERINFO結(jié)構(gòu)指針 時(shí),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;當(dāng)啟用或禁用菜單項(xiàng)和工具欄按鈕時(shí),將使用該附加功能, 在下文中討論。接著, 在一個(gè)稱為命令傳遞的過(guò)程中,命令消息和控件通知被提供給一些類。命令傳遞OnCmdMsg( ) 實(shí)際上是CCmdTarget的成員函數(shù),而不是CWnd的成員函數(shù)。認(rèn)識(shí)這一點(diǎn)很重要,因?yàn)樗?/p>
40、 任何從 CCmdTarget派生的類接收一個(gè)命令消息,即使那些沒(méi)有一個(gè)窗口的類也可以。例如,文檔類沒(méi)有相關(guān)聯(lián)的窗口,它依賴視圖類顯示它的文檔。但是一個(gè)文檔 類是處理一個(gè)裝載或保存命令的最 地方,因此,雖然一個(gè)文檔類不能處理類似于W M _ C R E AT E或 W M _ D E S T R O Y令 消 息。 但 OnCmdMsg( )它 處 理 類 似于WM_D和WM_NOTIFY令消息。CWnd本身是從CCmdTarget派生而來(lái)的,因此, 它也能支持命令消息,如圖3-5所示。在所有的主應(yīng)用程序類(應(yīng)用程序、框架、視圖和文檔類)中,MFC通過(guò)重載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窗口 沒(méi)找到任何東西,則調(diào)用文OnSaveFile( ),則調(diào)用它進(jìn)程檔類中的OnCmdMsg( )圖3-5 CCmdTarget支持沒(méi)有窗口的MFC對(duì)象的消息映像OnCmdMsg( )命令傳遞主菜單發(fā)送ID_ FILE_SAVE消息到框架窗口進(jìn)程發(fā)送到MFC類 令消息按下面的順序傳遞到所列類中CFrameWnd擁有輸入焦點(diǎn)的所有Cview的派生類它自身的消息映像所有CwinApp的派生類CMDIFrameWnd擁有輸入焦點(diǎn)的所有CMDICHildWnd的派生類擁有輸入焦點(diǎn)的所有Cview的派生類它自身的消息映像所
43、有CwinApp的派生類CMDIChildWnd它自身的消息映像CView它自身的消息映像所有CDocument的派生類CDocument它自身的消息映像所有CDocumentTemplate的派生類CDialog它自身的消息映像它的父類的消息映像它的線程的消息映像CPropertySheet它自身的消息映像 它的父類的消息映像它的線程的消息映像傳遞效果具有累積性。被發(fā)送到 CMDIFrame Wnd 令消息,首先被提供給有效的CMDIFrameWnd中的消息映像,接著給有效的 CView、有效CView的CDocument、那個(gè)文檔的CDocTemplate、CMDIFrameWnd自身的消
44、息映像,最后給CWinApp。一旦OnCmdMsg( ) 找到一個(gè)消息處理函數(shù),命令傳遞就停止。在前面的例子中,如果OnCmdMsg( ) 在CDocument中找到一個(gè)處理函數(shù),它將用命令消息調(diào)用該處理函數(shù)并返回結(jié)果,而不用繼續(xù)傳遞給CDocTemplate。消息映像宏雖然命令消息和控件通知被傳遞的 是相同的,但是它們預(yù)定義的消息映像宏卻是不同令消息采用的形式為:ON_D( )而控件通知采用的形式為: ON_CONTROL( )為WM_D通知ON_NOTIFY( )為WM_NOTIFY通知參見(jiàn)附錄B的詳細(xì)列表。參見(jiàn)圖3-6。 AfxWndProc( )找到擁有該窗口的類對(duì)象,并調(diào)用AfxWn
45、dCallProc( ) OnWndMsg()發(fā)送WM_COM- MAND消息到OnNotify(),發(fā) 送WM_NOTIFY到OnNotify( ), 而為剩下的消息在找到的類的消息映像中尋找一個(gè)處理函數(shù) WindowProc( )調(diào)用OnWndMsg( )根據(jù)類的類型, O n CmdMsg()可能調(diào)用其他類中OnCmdMsg()重載函數(shù)。否則,在該類的消息映像中搜索一個(gè)處理函數(shù) 發(fā)送到MFC AfxWndCallproc( )保 任何未被OnWnd Msg()處 Ond( ) 和OnNotify()把控件通創(chuàng)建的窗口中的消息都被AfxWndProc( ) 處理存消息后調(diào)用找到的類的Win
46、dowProc( ), 從現(xiàn)在起,所有被調(diào)用的函數(shù)都可以被重載理的消息被發(fā)送到DefWindowProc( )知反射回到類(未顯示出來(lái))。任何未被反射的消息被發(fā)送到OnCmdMsg( )通過(guò)完成所有這些過(guò)程,消息可以在類中被處理, 控件以被反射回到它們的控件,而命令消息可以被傳遞到應(yīng)用程序的任何地方圖3-6 描述MFC如何處理接受的3.7 處理用戶界面的對(duì)象剛剛討論過(guò)的一些成員函數(shù)也被 M F C用來(lái)更新用戶界面的狀態(tài)。具體地講, M F C用OnCmdMsg( )來(lái)啟用、禁用或檢查一個(gè)菜單中的所有菜單項(xiàng)和條中的所有控件 (工具欄、條和狀態(tài)欄)。無(wú)論何時(shí)打開(kāi)一個(gè)菜單項(xiàng), MFC更新菜單項(xiàng)的狀態(tài)
47、;每當(dāng)應(yīng)用程序空閑時(shí),它就更新條中控件的狀態(tài)。對(duì)于任一, M F C 進(jìn)入一個(gè)循環(huán),在該循環(huán)中為每個(gè)菜單項(xiàng)或條控件調(diào)用OnCmdMsg( ),最多可達(dá)兩次。第一次調(diào)用OnCmdMsg( )時(shí),應(yīng)用程序可以啟用或禁用菜單項(xiàng)或控件;如果不能為請(qǐng)求的行為提供一個(gè)特定的用戶界面處理函數(shù),則 OnCmdMsg( )被第二次調(diào)用,以檢查菜單項(xiàng)或控件究竟有沒(méi)有一個(gè)消息處理函數(shù),如果沒(méi)有, OnCmdMsg( ) 將自動(dòng)禁用菜單項(xiàng)或控件。注意如果想關(guān)閉這一自動(dòng)禁用特性,可以將CMainFrame類中的m_bAutoEnable設(shè)為FALSE。但是,這對(duì)工具欄不起作用。當(dāng)OnCmdMsg( )被調(diào)用,并應(yīng)用程序
48、更新界面時(shí),它被賦予如下參數(shù):OnCmdMsg(nID, CN_UPDATE_D_UI, CCmdUI *pCmdUI, NULL); nID是需要更新的菜單項(xiàng)或條控件的控件 ID。 *pCmdUI指向一個(gè)類,該類包含應(yīng)用程序更新菜單項(xiàng)和控件的成員函數(shù)。接著,按命令消息中相同的次序, OnCmdMsg( ) 仔細(xì)查看相同的消息映像,直到發(fā)現(xiàn)一個(gè)特定的用戶界面消息處理函數(shù)。處理CN_UPDATE_D_UI的預(yù)定義的宏是:ON_UPDATE_D_UI(id, Handler);對(duì)于某一范圍內(nèi)的控件ID,預(yù)定義的宏是:ON_UPDATE_D_UI_RANGE(id, idLast, Handler)
49、;對(duì)于每個(gè)宏,處理函數(shù)有相同的格式:void Handler(CCmdUI *pCmdUI)pCmdUI-Enable(pFlag);CCmdUI對(duì)象包含如下重要的成員變量和函數(shù): m_nID是控件ID,當(dāng)某個(gè)范圍的控件ID可以用相同的處理函數(shù)更新時(shí),它對(duì)第二宏格 式是有用的。 Enable (BOOL bOn),如果bOn設(shè)為FALSE,將使菜單項(xiàng)或控件無(wú)效。 SetCheck (int nCheck),如果nCheck為1,則將檢查菜單項(xiàng)。 SetRadio (BOOL bOn),更新單選按鈕。 SetText (LPCTSTR string),設(shè)置控件或菜單項(xiàng)的文本。這些成員函數(shù)中的每一
50、個(gè)都被重載,以便當(dāng)菜單被更新時(shí),調(diào)用禁用菜單項(xiàng)的代碼,當(dāng) 一個(gè) 條被更新時(shí),調(diào)用禁用控件的代碼。當(dāng)OnCmdMsg( ) 被第二次調(diào)用來(lái)確定應(yīng)用程序是否有一個(gè)菜單項(xiàng)或控件的處理函數(shù)時(shí), 它被賦予如下變量:BOOL bHandler=OnCmdMsg(nID, CN_D, CCmdUI *pCmdUI, AFX_CMDHANDLERINFO *info);在第一次看到OnCmdMsg( ) 的變量時(shí)已提及,一個(gè) AFX_CMDHANDLERINFO結(jié)構(gòu)的指針,使OnCmdMsg( ) 只查找一個(gè)消息處理函數(shù)而不執(zhí)行。如果返回值為 FALSE,則沒(méi)有處理函數(shù),菜單項(xiàng)和控件被禁用。關(guān)于用CCmdUI
51、類對(duì)象更新用戶界面的例子,參見(jiàn)例 16、例17、例18。3.8 創(chuàng)建自定義窗口消息從WM_NULL到WM_USER有70個(gè)系統(tǒng)定義的窗口消息。根據(jù) 的意愿,用戶可以創(chuàng)建兩種自定義的窗口消息:靜態(tài)定義的大于 WM_USER值的窗口消息,在給定字符串標(biāo)識(shí)符時(shí) 動(dòng)態(tài)定義的窗口消息。注意 請(qǐng)記住,窗口消息主要是為窗口內(nèi)在運(yùn)行機(jī)制設(shè)計(jì)的,而不是為處理用戶命令設(shè)計(jì)的。如果只想告訴應(yīng)用程序的一部分或別的應(yīng)用程序處理一個(gè)用戶命令,那么用已定義的WM_D窗口消息和一個(gè)新令I(lǐng)D。3.8.1 靜態(tài)分配的窗口消息Windows保留了0和WM_USER-1之間的整數(shù)范圍,作為系統(tǒng)定義的窗口消息;還有一個(gè)從WM_USER
52、一直到OX7fff的整數(shù)范圍,留給自定義消息用??梢杂靡粋€(gè)簡(jiǎn)單的 #define語(yǔ)句定義消息:#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)通過(guò)修改下面的宏,可以定義完全屬于用戶的消息映像宏。#define ON_MY_MESSAGE1() WM_MYMESSAGE1, 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(AFX_PMSGW) (LRESULT (AFX_MSG_CALL CWnd:*)(WPARAM, PARAM)&OnMyMessage1,在這里,自動(dòng)賦予處理函數(shù)名為 OnMessage1,但還是具有相同的調(diào)用變量。為了改變調(diào)用變量,在AfXMSG_.H文件中尋找一個(gè)更加合適的nSig值,并替換AfxSig_lwl,然后修改宏 中的最后一行
54、,以 新變量。有關(guān)例子參見(jiàn)例 62。3.8.2 動(dòng)態(tài)分配的窗口消息為了在應(yīng)用程序間發(fā)送消息,應(yīng)該用下面的語(yǔ)句創(chuàng)建一個(gè)基于描述性字符串的新的窗口 消息。UINT wm_MyMessage1=:RegisterWindowMessage(LPCSTR Identifier); Identifier是描述性字符串。 wm_MyMessage1是在0xc000和0xffff之間的一個(gè)動(dòng)態(tài)分配的窗口消息。為了處理在消息映像中的消息,可以用: ON_REGISTERED_MESSAGE(wm_MyMessage1,Handler)把由RegisterWindowMessage( )分配的值傳送給它。該消息的處理函數(shù)看起來(lái)像:LRESULT Handler(WPARAM, LPARAM)一個(gè)動(dòng)態(tài)分配的窗口消息使得應(yīng)用程序間窗口消息的維
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 單位管理制度呈現(xiàn)合集【人力資源管理篇】
- 2024年廠年度勞動(dòng)競(jìng)賽的工作總結(jié)
- 《廣告的社會(huì)功能》課件
- 第1單元 中華人民共和國(guó)的成立與鞏固 (B卷·能力提升練)(解析版)
- 《孟子生平簡(jiǎn)介》課件
- 《杜絕校園欺凌》課件
- 超市客服話務(wù)員工作總結(jié)
- 探索生態(tài)之謎
- 2023年項(xiàng)目安全培訓(xùn)考試題(能力提升)
- 2023年項(xiàng)目部治理人員安全培訓(xùn)考試題附完整答案(必刷)
- 遼海版六年級(jí)音樂(lè)上冊(cè)第8單元《3. 演唱 姐妹們上場(chǎng)院》教學(xué)設(shè)計(jì)
- 形勢(shì)任務(wù)教育宣講材料第一講——講上情
- 物業(yè)安全員考核實(shí)施細(xì)則
- 中國(guó)地質(zhì)大學(xué)(武漢)教育發(fā)展基金會(huì)籌備成立情況報(bào)告
- 第四章破產(chǎn)法(破產(chǎn)法)教學(xué)課件
- PE拖拉管施工方案標(biāo)準(zhǔn)版
- 7725i進(jìn)樣閥說(shuō)明書(shū)
- 鐵路建設(shè)項(xiàng)目施工企業(yè)信用評(píng)價(jià)辦法(鐵總建設(shè)〔2018〕124號(hào))
- 時(shí)光科技主軸S系列伺服控制器說(shuō)明書(shū)
- 無(wú)機(jī)非金屬材料專業(yè) 畢業(yè)設(shè)計(jì)論文 年產(chǎn)240萬(wàn)平方米釉面地磚陶瓷工廠設(shè)計(jì)
- 社會(huì)組織績(jī)效考核管理辦法
評(píng)論
0/150
提交評(píng)論