反射消息

在對話框的OnInitDialog函數中創建反射控件,則沒有LVN_GETDISPINFOW 消息產生,即不能相應OnGetdispinfo函數。

而在OnCreate中創建反射控件,就可以。

 

原因未知???待查。

 

 

Windows控件消息反射

TN062: Message Reflection for Windows Controls

本技術文檔解釋了消息反射,MFC 4.0的新特性,並指導讀者創建一個簡單的、可重用的、使用了消息反射的控件。

本文並不討論適用於ActiveX控件(通常稱爲OLE控件)的消息反射。請參看Visual C++ Programmer’s GuideActiveX Controls: Subclassing a Windows Control一文。

什麼是消息反射?

Windows控件頻繁地向其父窗口發送消息。例如,很多控件發送控件顏色提醒消息(WM_CTLCOLOR或其變種)給其父窗口,通知父窗口提供畫刷,以重畫控件的背景。

在4.0版本前的Windows和MFC中,父窗口,通常是一個對話框,負責處理這些消息。這意味着處理消息的代碼放置在父窗口類中,並且需要在任何需要處理這個消息的窗口中重複寫這些代碼。在這種情況下,每個對話框都必須爲其內部的控件定製背景色而處理提醒消息。若控件類可以自己處理其背景顏色,那麼處理代碼的重用就會變得非常容易了。

在MFC 4.0中,舊的機制仍將正常運行,即父窗口可以處理提醒消息。但同時,MFC 4.0提供了消息反射,允許這些提醒消息既可在子控件中處理又可在其父窗口中處理,使得代碼重用更加容易。以控件背景顏色爲例,現在可以創建一個控件,自己來處理WM_CTLCOLOR的反射消息,一切都不用依靠其父窗口。(注意,消息反射是由MFC實現的,而非Windows,因此要使用消息反射,父窗口必須繼承於CWnd。

舊版本的MFC爲一些消息提供了一些虛函數,使得消息的處理與消息反射機制相似。例如自畫列表框(owner-drawn list boxes)的消息(WM_DRAWITEM之類)。新的消息反射機制是通用並且一致的。

消息映射向後兼容MFC 4.0之前的版本。

若在父窗口提供了某一個或是一組指定消息的處理函數,它將覆蓋反射的消息處理函數。在自己的消息處理函數中不應調用父窗口的處理函數。例如: 若在對話框處理WM_CTLCOLOR消息,則此處理函數將會覆蓋所有反射消息的處理函數。

若在父窗口類中提供了某一個或一組WM_NOTIFY消息,則消息處理函數僅在子窗口沒有使用ON_NOTIFY_REFLECT()處理反射消息時被調用。若在消息映射中使用ON_NOTIFY_REFLECT_EX(),消息句柄可能會或可能不會允許父窗口處理這些消息。若處理函數返回TRUE,則父窗口也會處理此消息,而返回FALSE,則不允許父窗口處理。注意,反射消息在提醒消息前被處理。

當WM_NOTIFY被髮送時,首先反射給控件來處理。而其他消息被髮送時,父窗口將首先處理,然後子控件纔會接收到反射的消息。要讓子控件處理這些反射的消息,需要一個消息處理函數,及消息映射實體。

反射消息的消息映射宏與普通的提醒消息稍有不同:它在普通的名字後加上了_REFLECT。例如,要在父窗口處理WM_NOTIFY消息,需要在父窗口的消息映射中加上ON_NOTIFY。而要在子控件裏處理反射消息,則需要在子控件裏使用ON_NOTIFY_REFLECT宏。在一些情況下,參數也有可能不同。注意,ClassWizard一般都可以正確地添加反射消息及其函數體。

參看TN061:ON_NOTIFY及WM_NOTIFY消息瞭解WM_NOTIFY消息。

反射消息的消息映射及處理函數原型

要處理控件提醒消息的反射消息,使用下表列出的消息映射宏及函數原型。ClassWizard一般都可以正確地添加反射消息及其函數體。參看Visual C++ Programmer’s GuideDefining a Message Handler for a Reflected Message,以瞭解如何定義反射消息的處理函數。

要將消息名轉化爲反射宏名,在消息名前面加上ON_,並在其後面加上_REFLECT即可。例如:WM_CTLCOLOR的反射宏名爲ON_WM_CTLCOLOR_REFLECT。(要查看哪些消息可以被反射,將下表的宏作逆變換。)

這種命名規則的特例有以下三個:

l        WM_COMMAND的反射宏爲ON_CONTROL_REFLECT

l        WM_NOTIFY的反射宏爲ON_NITIFY_REFLECT

l        ON_UPDATE_COMMAND_UI的反射宏爲ON_UPDATE_COMMAND_UI_REFLECT

在上面三種特例下,必須指定處理函數名,而在其它情況下,必須使用標準的處理函數名。

函數參數及返回值的意義歸檔在其函數名,或函數名前加On下。例如CtlColor被歸檔在OnCtlColor中。一些反射消息的處理函數需要的參數比父窗口消息處理函數的更少。直接將本表中的名字與文檔中的形參名相對應即可。

映射實體

函數原型

ON_CONTROL_REFLECT(wNotifyCode, memberFxn)

afx_msgvoidmemberFxn();

ON_NOTIFY_REFLECT(wNotifyCode, memberFxn)

afx_msgvoidmemberFxn(NMHDR * pNotifyStruct, LRESULT* result);

ON_UPDATE_COMMAND_UI_REFLECT(memberFxn)

afx_msgvoidmemberFxn(CCmdUI* pCmdUI);

ON_WM_CTLCOLOR_REFLECT()

afx_msgHBRUSHCtlColor(CDC* pDC, UINTnCtlColor);

ON_WM_DRAWITEM_REFLECT()

afx_msgvoidDrawItem(LPDRAWITEMSTRUCTlpDrawItemStruct);

ON_WM_MEASUREITEM_REFLECT()

afx_msgvoidMeasureItem(LPMEASUREITEMSTRUCTlpMeasureItemStruct);

ON_WM_DELETEITEM_REFLECT()

afx_msgvoidDeleteItem(LPDELETEITEMSTRUCTlpDeleteItemStruct);

ON_WM_COMPAREITEM_REFLECT()

afx_msgintCompareItem(LPCOMPAREITEMSTRUCTlpCompareItemStruct);

ON_WM_CHARTOITEM_REFLECT()

afx_msgintCharToItem(UINTnKey, UINTnIndex);

ON_WM_VKEYTOITEM_REFLECT()

afx_msgintVKeyToItem(UINTnKey, UINTnIndex);

ON_WM_HSCROLL_REFLECT()

afx_msgvoidHScroll(UINTnSBCode, UINTnPos);

ON_WM_VSCROLL_REFLECT()

afx_msgvoidVScroll(UINTnSBCode, UINTnPos);

ON_WM_PARENTNOTIFY_REFLECT()

afx_msgvoidParentNotify(UINTmessage, LPARAMlParam);

ON_NOTIFY_REFLECT及ON_CONTROL_REFLECT宏有以下變異體,允許其被多個對象處理(例如控件及其父窗口)。

映射實體

函數原型

ON_NOTIFY_REFLECT_EX(wNotifyCode, memberFxn)

afx_msgBOOLmemberFxn(NMHDR * pNotifyStruct, LRESULT* result);

ON_CONTROL_REFLECT_EX(wNotifyCode, memberFxn)

afx_msgBOOLmemberFxn();

處理反射消息: 一個重用控件的例子

本例創建了一個可重用的控件CYellowEdit。此控件與普通的文本框相似,只是它在黃色背景上顯示黑色的文字。很容易爲CYellowEdit添加成員函數,以使之顯示不同的背景顏色。

實現步驟如下:

1.      在工程中創建一個新的對話框。請參見Visual C++ User’s Guide以瞭解更多信息。

爲開發一個可重用的控件,應有一個應用程序。若沒有現成的應用程序,使用AppWizard創建一個基於對話框的應用程序。

2.      加載工程後,使用ClassWizard創建一個繼承於CEdit的新類CYellowEdit。選定“Add to Component Gallery”複選框。

3.      在CYellowEdit類裏添加三個變量。前兩個變量爲COLORREF類型,以存放文本顏色及背景顏色。第三個變量是一個CBrush對象,以存放背景畫刷。CBrush可以只創建一次,之後就直接引用,並且在CYellowEdit被銷燬的時候自動銷燬。

4.      在構造函數裏初始化成員變量:

CYellowEdit::CYellowEdit()

{

    m_clrText = RGB(0, 0, 0);

    m_clrBkgnd = RGB(255, 255, 0);

    m_brBkgnd.CreateSolidBrush(m_clrBkgnd);

}

 

使用ClassWizard,在CYellowEdit裏添加一個WM_CTLCOLOR反射消息的處理函數。注意,消息名前的等號表示此消息已被反射。這在Visual C++ Programmer’s GuideDefining a Message Handler for a Reflected Message有相應描述。

ClassWizard將添加以下的消息映射宏及函數:

ON_WM_CTLCOLOR_REFLECT()

 

// Note: other code will be in between….

 

HBRUSHCYellowEdit::CtlColor(CDC* pDC, UINTnCtlColor)

{

    // TODO: Change any attributes of the DC here

   

    // TODO: Return a non-NULL brush if the

    //    parent’s handler should not be called

    returnNULL;

}

 

用下面的代碼替換函數體。這些代碼指定了文字顏色,文字背景顏色以及控件其餘部分的背景顏色。

pDC->SetTextColor(m_clrText);    // text

pDC->SetBkColor(m_clrBkgnd);    // text bkgnd

returnm_brBkgnd;                // ctl bkgnd

 

在對話框裏創建一個文本框,按住CTRL鍵的同時雙擊文本框控件,以將其與一成員變量綁定。在Add Member Variable對話框中,輸入變量名,選擇”控件”,並選擇變量類型爲CYellowEdit。不要忘了設置對話框的TAB順序。並且要在對話框的頭文件中包含CYellowEdit的頭文件。

編譯並運行應用程序,文本框將有一個黃色的背景。

現在可以使用Component Gallery將CYellowEdit控件類添加到其它工程中去了。

 

 

 

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