TN062:Windows 控制項的訊息反映
注意
下列技術提示自其納入線上文件以來,未曾更新。 因此,有些程序和主題可能已過期或不正確。 如需最新資訊,建議您在線上文件索引中搜尋相關的主題。
此技術附注描述訊息反映,這是 MFC 4.0 中的新功能。 它也包含建立使用訊息反映之簡單可重複使用控制項的指示。
此技術注意事項不會討論訊息反映,因為它適用于 ActiveX 控制項(先前稱為 OLE 控制項)。 請參閱 ActiveX 控制項:子類別化 Windows 控制項 一文 。
什麼是訊息反思
Windows 控制項經常將通知訊息傳送至其父視窗。 例如,許多控制項會將控制項色彩通知訊息(WM_CTLCOLOR或其其中一個變體)傳送至其父系,讓父控制項提供筆刷來繪製控制項的背景。
在 Windows 和 4.0 版之前的 MFC 中,父視窗通常是對話方塊負責處理這些訊息。 這表示處理訊息的程式碼必須位於父視窗的 類別中,而且必須在需要處理該訊息的每個類別中重複。 在上述案例中,想要具有自訂背景之控制項的每個對話方塊都必須處理控制項色彩通知訊息。 如果控制項類別可以撰寫來處理自己的背景色彩,則重複使用程式碼會更容易。
在 MFC 4.0 中,舊機制仍可運作 — 父視窗可以處理通知訊息。 不過,MFC 4.0 提供稱為「訊息反映」的功能,可讓這些通知訊息在子控制項視窗或父視窗或兩者中處理,以利重複使用。 在控制項背景色彩範例中,您現在可以撰寫控制項類別,藉由處理反映的WM_CTLCOLOR訊息來設定自己的背景色彩,而不需要依賴父系。 (請注意,由於訊息反映是由 MFC 實作,而不是由 Windows 實作,父視窗類別必須衍生自 CWnd
,訊息反映才能運作。
舊版的 MFC 會提供一些訊息的虛擬函式,例如擁有者繪製清單方塊的訊息(WM_DRAWITEM等等)的虛擬函式,以類似訊息反映。 新的訊息反映機制已一般化且一致。
訊息反映與針對 4.0 之前的 MFC 版本所撰寫的程式碼回溯相容。
如果您已在父視窗的 類別中為特定訊息或訊息範圍提供處理常式,它會覆寫相同訊息的反映訊息處理常式,前提是您不會在自己的處理常式中呼叫基類處理常式函式。 例如,如果您在對話方塊類別中處理WM_CTLCOLOR,您的處理將會覆寫任何反映的訊息處理常式。
如果在父視窗類別中,您提供特定WM_NOTIFY訊息或WM_NOTIFY訊息 ON_NOTIFY_REFLECT()
範圍的處理常式,則只有在子控制項透過 傳送這些訊息時,才會呼叫處理常式。 如果您在 ON_NOTIFY_REFLECT_EX()
訊息對應中使用 ,訊息處理常式可能會或可能不允許父視窗處理訊息。 如果處理常式傳 回 FALSE ,則訊息也會由父代處理,而傳回 TRUE 的呼叫則不允許父代處理它。 請注意,反映的訊息會在通知訊息之前處理。
傳送WM_NOTIFY訊息時,控制項會提供第一個處理它的機會。 如果傳送任何其他反映的訊息,父視窗就會有第一個處理它的機會,而控制項將會收到反映的訊息。 若要這樣做,它需要處理常式函式和控制項類別訊息對應中適當的專案。
反映訊息的訊息對應宏與一般通知稍有不同:它 已附加至其一般名稱_REFLECT 。 例如,若要處理父系中的WM_NOTIFY訊息,您可以使用父系訊息對應中的宏ON_NOTIFY。 若要處理子控制項中的反映訊息,請在子控制項的訊息對應中使用 ON_NOTIFY_REFLECT 宏。 在某些情況下,參數也不同。 請注意,ClassWizard 通常可以為您新增訊息對應專案,並提供具有正確參數的基本架構函式實作。
如需新WM_NOTIFY訊息的相關資訊,請參閱 TN061:ON_NOTIFY 和 WM_NOTIFY 訊息 。
反思訊息的訊息對應專案和處理常式函式原型
若要處理反映的控制項通知訊息,請使用下表所列的訊息對應宏和函式原型。
ClassWizard 通常可以為您新增這些訊息對應專案,並提供基本架構函式實作。 如需如何定義反映訊息之處理常式的詳細資訊,請參閱 定義反思訊息的訊息 處理常式。
若要從訊息名稱轉換成反映的宏名稱,請在前面 加上ON_ 並附加 _REFLECT 。 例如,WM_CTLCOLOR會變成ON_WM_CTLCOLOR_REFLECT。 (若要查看哪些訊息可以反映,請對下表中的宏專案執行相反的轉換。
上述規則的三個例外如下:
WM_COMMAND通知的宏ON_CONTROL_REFLECT。
WM_NOTIFY反映的宏是ON_NOTIFY_REFLECT。
ON_UPDATE_COMMAND_UI反映的宏ON_UPDATE_COMMAND_UI_REFLECT。
在上述每個特殊案例中,您必須指定處理常式成員函式的名稱。 在其他情況下,您必須使用處理程式函式的標準名稱。
函式的參數和傳回值的意義會記載在函式名稱底下,或是前面 加上 On 的函式名稱。 例如, CtlColor
記載于 OnCtlColor
中。 數個反映的訊息處理常式需要比父視窗中類似處理常式更少的參數。 只要將下表中的名稱與檔中的正式參數名稱相符。
對應項目 | 函式原型 |
---|---|
ON_CONTROL_REFLECT( wNotifyCode ,) memberFxn |
afx_msg void memberFxn ( ): |
ON_NOTIFY_REFLECT( wNotifyCode ,) memberFxn |
afx_msg void memberFxn (NMHDR * pNotifyStruct 、LRESULT * 結果): |
ON_UPDATE_COMMAND_UI_REFLECT( memberFxn ) |
afx_msg void memberFxn ( CCmdUI): * pCmdUI |
ON_WM_CTLCOLOR_REFLECT( ) | afx_msg HBRUSH CtlColor ( CDC pDC * , UINT): nCtlColor |
ON_WM_DRAWITEM_REFLECT( ) | afx_msg void DrawItem (LPDRAWITEMSTRUCT lpDrawItemStruct ): |
ON_WM_MEASUREITEM_REFLECT( ) | afx_msg void MeasureItem (LPMEASUREITEMSTRUCT lpMeasureItemStruct ): |
ON_WM_DELETEITEM_REFLECT( ) | afx_msg void DeleteItem (LPDELETEITEMSTRUCT lpDeleteItemStruct ): |
ON_WM_COMPAREITEM_REFLECT( ) | afx_msg int CompareItem (LPCOMPAREITEMSTRUCT lpCompareItemStruct ): |
ON_WM_CHARTOITEM_REFLECT( ) | afx_msg int CharToItem ( UINT nKey , UINT): nIndex |
ON_WM_VKEYTOITEM_REFLECT( ) | afx_msg int VKeyToItem ( UINT nKey , UINT): nIndex |
ON_WM_HSCROLL_REFLECT( ) | afx_msg void HScroll ( UINT nSBCode , UINT: nPos |
ON_WM_VSCROLL_REFLECT( ) | afx_msg void VScroll ( UINT nSBCode , UINT): nPos |
ON_WM_PARENTNOTIFY_REFLECT( ) | afx_msg void ParentNotify (UINT message , LPARAM): lParam |
ON_NOTIFY_REFLECT和ON_CONTROL_REFLECT宏有變化,可讓多個物件(例如控制項及其父代)處理指定的訊息。
對應項目 | 函式原型 |
---|---|
ON_NOTIFY_REFLECT_EX( wNotifyCode ,) memberFxn |
afx_msg BOOL memberFxn (NMHDR * pNotifyStruct 、LRESULT * 結果): |
ON_CONTROL_REFLECT_EX( wNotifyCode ,) memberFxn |
afx_msg BOOL memberFxn ( ): |
處理反思訊息:可重複使用控制項的範例
這個簡單的範例會建立稱為 CYellowEdit
的可重複使用控制項。 控制項的運作方式與一般編輯控制項相同,不同之處在于它在黃色背景上顯示黑色文字。 加入可讓 CYellowEdit
控制項顯示不同色彩的成員函式很容易。
嘗試建立可重複使用控制項的範例
在現有的應用程式中建立新的對話方塊。 如需詳細資訊,請參閱 對話方塊編輯器 主題。
您必須有應用程式,才能開發可重複使用的控制項。 如果您沒有要使用的現有應用程式,請使用 AppWizard 建立對話式應用程式。
將專案載入 Visual C++ 後,請使用 ClassWizard 建立以 為基礎的
CEdit
新CYellowEdit
類別。將三個成員變數新增至類別
CYellowEdit
。 前兩個是 COLORREF 變數,用來保存文字色彩和背景色彩。 第三個CBrush
物件會保留筆刷來繪製背景。 物件CBrush
可讓您建立筆刷一次,只是在之後參考它,並在控制項終結時CYellowEdit
自動終結筆刷。撰寫建構函式,以初始化成員變數,如下所示:
CYellowEdit::CYellowEdit() { m_clrText = RGB(0, 0, 0); m_clrBkgnd = RGB(255, 255, 0); m_brBkgnd.CreateSolidBrush(m_clrBkgnd); }
使用 ClassWizard,將反映WM_CTLCOLOR訊息的處理常式新增至您的
CYellowEdit
類別。 請注意,您可以在訊息清單中訊息名稱前面等號表示訊息已反映。 定義反思訊息 的訊息處理常式中所述 。ClassWizard 會為您新增下列訊息對應宏和基本架構函式:
ON_WM_CTLCOLOR_REFLECT() // Note: other code will be in between.... HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor) { // TODO: Change any attributes of the DC here // TODO: Return a non-NULL brush if the // parent's handler should not be called return NULL; }
使用下列程式碼取代函式主體。 程式碼會指定控制項其餘部分的文字色彩、文字背景色彩和背景色彩。
pDC->SetTextColor(m_clrText); // text pDC->SetBkColor(m_clrBkgnd); // text bkgnd return m_brBkgnd; // ctl bkgnd
在對話方塊中建立編輯控制項,然後在按住控制項鍵時按兩下編輯控制項,將其附加至成員變數。 在 [新增成員變數] 對話方塊中,完成變數名稱,然後選擇類別的 [控制項],然後針對變數類型選擇 「CYellowEdit」。 別忘了在對話方塊中設定定位順序。 此外,請務必在
CYellowEdit
對話方塊的標頭檔中包含 控制項的標頭檔。建置並執行您的應用程式。 編輯控制項會有黃色背景。