MFC 技術注意第62條的翻譯 (轉)

worldblog發表於2007-12-09
MFC 技術注意第62條的翻譯 (轉)[@more@]

技術注意062: 的訊息反射
TN062: Message Reflection for Windows Controls

本技術注意講述了訊息反射,一個 MFC4.0 中的新特色。同時講述了使用訊息反射建立一個簡單可重用控制元件的指導。
This technical note describes message reflection, a new feature in MFC 4.0. It also contains directions for creating a simple reusable control that uses message reflection.

本文並沒有就 控制元件(以前稱為 OLE 控制元件)如何進行訊息反射的。有關這方面的資料請參見《ActiveX Controls: Subclassing a Windows Control in Visual C++ Programmer's Gu》。
This technical note does not discuss message reflection as it applies to ActiveX controls (formerly called OLE controls). Please see the articleActiveX Controls: Subclassing a Windows Control in Visual C++ Programmer's Guide.

什麼是訊息反射?
What Is Message Reflection?

視窗不斷地頻繁地傳送通知訊息給其父視窗。 例如:許多控制元件會傳送控制元件顏色通知訊息(WM_CTLCOLOR 或它的一個變體)給其父視窗以允許其父視窗來提供一個繪製控制元件背景的刷子。

Windows controls frequently send notification messages to their parent windows. For instance, many controls send a control color notification message (WM_CTLCOLOR or one of its variants) to their parent to allow the parent to supply a brush for painting the background of the control.

在 Windows 和 MFC4.0 以前的版本中,父視窗——通常是一個對話方塊,會來響應處理這些訊息。這就意味著處理這些訊息的程式碼需要在父視窗類中實現,而且對於每一個類都要處理這些訊息。在上述的情況下,每個需要自定義背景控制元件的對話方塊都不得不處理控制元件顏色通知訊息。如果一個控制元件可以處理自己的背景顏色,而且可以被重用,事情將變的簡單的多。
In Windows and in MFC prior to version 4.0, the parent window, often a dialog box, is responsible for handling these messages. This means that the code for handling the message needs to be in the parent window’s class and that it has to be duplicated in every class that needs to handle that message. In the case above, every dialog box that wanted controls with custom backgrounds would have to handle the control color notification message. It would be much easier to reuse code if a control class could be written that would handle its own background color.

在 MFC 4.0 中,舊的訊息機制仍然在工作 —— 父視窗可以處理通知訊息。另外同時,MFC 4.0 透過提供了一種稱為“訊息反射”的新機制使的重複使用變的容易多了。訊息反射允許這些通知訊息既能夠被控制元件自身處理,也能夠被其父視窗來處理。在上述控制元件背景顏色例子中,現在你就既可以透過被髮射過來的WM_CTLCOLOR訊息自己寫一個能夠處理背景顏色的控制元件類,所有的一切就不再依靠其父視窗了。(請注意,既然這個訊息反射只能在 MFC 實現,不是 Windows 的。所以父視窗必須派生於CWnd,這樣訊息反射才能正常工作)。
In MFC 4.0, the old mechanism still works—parent windows can handle notification messages. In addition, however, MFC 4.0 facilitates reuse by providing a feature called “message reflection” that allows these notification messages to be handled in either the child control window or the parent window, or in both. In the control background color example, you can now write a control class that sets its own background color by handling the reflected WM_CTLCOLOR message—all without relying on the parent. (Note that since message reflection is implemented by MFC, not by Windows, the parent window class must be derived from CWnd for message reflection to work.)

MFC 舊版本透過為一些訊息提供虛的機制部分實現了類似的功能,最典型的就是自繪製的列表框(WM_DRAWITEM等等)。然後新的訊息反射機制更通用和持久。
Older versions of MFC did something similar to message reflection by providing virtual functions for a few messages, such as messages for owner-drawn list boxes (WM_DRAWITEM, and so on). The new message reflection mechanism is generalized and consistent.

訊息訊息機制向後與MFC4.0版本前的程式碼相相容。
Message reflection is backward compatible with code written for versions of MFC previous to 4.0.
如果你在控制元件的父視窗類中為一個或一定範圍特定的訊息提供了一個處理函式,對於同樣的訊息,如果在您的處理中您並沒有其基類的處理函式它就會覆蓋掉被反射的訊息處理。例如,如果你在一個對話方塊類中試圖處理 WM_CTLCOLOR,您的處理將覆蓋掉任何被反射的訊息處理函式。
If you have supplied a handler for a specific message, or for a range of messages, in your parent window's class, it will override reflected message handlers for the same message provided you don't call the base class handler function in your own handler. For example, if you handle WM_CTLCOLOR in your dialog box class, your handling will override any reflected message handlers.

如果你在父視窗中為一個或一系列一定範圍的特定的 WM_NOTIFY 訊息提供一個處理函式,您的處理函式只有當這些傳送訊息的子控制元件透過ON_NOTIFY_REFLECT() 宏就不會有一個被反射訊息處理了。如果該處理返回 TRUE,訊息就也會給父視窗來處理,而如果它返回的是一個 FALSE值,就不會讓父視窗來處理該訊息。請注意:被反射的訊息是在通知訊息之前被處理。

If, in your parent window class, you supply a handler for a specific WM_NOTIFY message or a range of WM_NOTIFY messages, your handler will be called only if the child control sending those messages does not have a reflected message handler through ON_NOTIFY_REFLECT(). If you use ON_NOTIFY_REFLECT_EX() in your message map, your message handler may or may not allow the parent window to handle the message. If the handler returns TRUE, the message will be handled by the parent as well, while a call that returns FALSE does not allow the parent to handle it. Note that the reflected message is handled before the notification message.

當一個 WM_NOTIFY 訊息被髮送後,控制元件就得到了第一次的機會來處理它。如果任何其他的被反射訊息被髮送,父視窗會有第一個機會來處理之,而控制元件將能接收被反射的訊息。為了達到這樣的目的,在控制元件類訊息對映中需要一個處理函式和一個合適的入口。
When a WM_NOTIFY message is sent, the control is offered the first chance to handle it. If any other reflected message is sent, the parent window has the first chance to handle it and the control will receive the reflected message. To do so, it will need a handler function and an appropriate entry in the control's class message map.

反射訊息的訊息對映宏與通常通知的訊息對映宏有點微小的區別:它需要在其常規名字中新增 _REFLECT。例如,為了在父視窗中處理 WM_NOTIFY 訊息,你可以在父視窗類的訊息對映中使用宏 ON_NOTIFY。而在子控制元件類中處理反射訊息,您必須使用 ON_NOTIFY_REFLECT 來響應訊息。在一些情形之中,引數也是不一樣的。請注意:ClassWizard(類嚮導)通常可以為你新增訊息入口,並提供了一個帶有正確引數的實現函式的大體。
The message-map macro for reflected messages is slightly different than for regular notifications: it has _REFLECT appended to its usual name. For instance, to handle a WM_NOTIFY message in the parent, you use the macro ON_NOTIFY in the parent’s message map. To handle the reflected message in the child control, use the ON_NOTIFY_REFLECT macro in the child control’s message map. In some cases, the parameters are different, as well. Note that ClassWizard can usually add the message-map entries for you and provide skeleton function implementations with correct parameters.

請參閱 TN061: 在新 WM_NOTIFY 訊息中的 ON_NOTIFY 與 WM_NOTIFY 資訊
See TN061: ON_NOTIFY and WM_NOTIFY Messages for information on the new WM_NOTIFY message.


反射訊息的訊息對映入口和處理函式原型
Message-Map Entries and Handler Function s for Reflected Messages

為了處理被反射過來的控制元件通知訊息,使用列於下表的訊息對映宏和函式原型。
To handle a reflected control notification message, use the message-map macrand function prototypes listed in the table below.

ClassWizard 通常能夠為你加入訊息對映入口併為您提供一個實現函式的骨架。請參見
《Defining a Message Handler for a Reflected Message in the Visual C++ Programmer's Guide》來獲得有關怎麼為反射訊息定義處理函式的資訊。
ClassWizard can usually add these message-map entries for you and provide skeleton function implementations. SeeDefining a Message Handler for a Reflected Message in the Visual C++ Programmer's Guide for information about how to define handlers for reflected messages.

為了把訊息名稱轉化為被反射的宏名稱,在訊息名稱前加 ON_,然後在訊息名稱後新增
_REFLECT。例如,WM_CTLCOLOR 相應的就轉變為 ON_WM_CTLCOLOR_REFLECT。
To convert from the message name to the reflected macro name, prepend ON_ and append _REFLECT. For example, WM_CTLCOLOR becomes ON_WM_CTLCOLOR_REFLECT. (To see which messages can be reflected, do the opposite conversion on the macro entries in the table below.)

上述規則[普遍通用,但是要注意有三個例外:
The three exceptions to the rule above are as follows:

用於 WM_COMMAND 通知的宏是 ON_CONTROL_REFLECT;
用於 WM_NOTIFY 通知的宏是 ON_NOTIFY_REFLECT;
用於 ON_UPDATE_COMMAND_UI 通知的宏是 ON_UPDATE_COMMAND_UI_REFLECT。

The macro for WM_COMMAND notifications is ON_CONTROL_REFLECT.
The macro for WM_NOTIFY reflections is ON_NOTIFY_REFLECT.
The macro for ON_UPDATE_COMMAND_UI reflections is ON_UPDATE_COMMAND_UI_REFLECT.

在上述特殊情形中,您必須指定處理成員函式的名字。而在其他情形中,您必須使用標準的處理函式名稱。
In each of the above special cases, you must specify the name of the handler member function. I
n the other cases, you must use the standard name for your handler function.
函式引數的意義和返回值的意思已經羅列於函式名稱之下或已經預先寫好了。例如,CtlColor 在文件中表示為 OnCtlColor。幾個被反射訊息處理函式需要的引數個數要比在其父視窗中相應的函式需要的引數要少。請參見下表中文件中的正式引數。

The meanings of the parameters and return values of the functions are documented under either the function name or the function name with On prepended. For instance, CtlColor is documented in OnCtlColor. Several reflected message handlers need fewer parameters than the similar handlers in a parent window. Just match the names in the table below with the names of the formal parameters in the documentation.

對映宏  入口  函式原型
ON_CONTROL_REFLECT( wNotifyCode, memberFxn )  afx_msg void memberFxn ( );
ON_NOTIFY_REFLECT( wNotifyCode, memberFxn )  afx_msg void memberFxn ( NMHDR * pNotifyStruct, LRESULT* result );
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 有幾個變體,以允許諸如控制元件及其父視窗多個來處理給定的訊息。

The ON_NOTIFY_REFLECT and ON_CONTROL_REFLECT macros have variations that allow more than one (such as the control and its parent) to handle a given message.

對映宏  入口 函式原型
ON_NOTIFY_REFLECT_EX( wNotifyCode, memberFxn )  afx_msg BOOL memberFxn ( NMHDR * pNotifyStruct, LRESULT* result );
ON_CONTROL_REFLECT_EX( wNotifyCode, memberFxn ) afx_msg BOOL memberFxn ( );


處理被反射的訊息:可重用控制元件的例子
Handling Reflected Messages: An Example of a Reusable control

這個簡單的例子建立了一個可重用的控制元件,叫 CYellowEdit。該控制元件與一個常規編輯控制元件的功能幾乎相同,不同就是它在黃色背景中顯示黑字。當然,你可以很容易地新增一些成員函式使之顯示不同的顏色。
This simple example creates a reusable control called CYellowEdit. The control works the same as a regular edit control except that it displays black text on a yellow background. It would be easy to add member functions that would allow the CYellowEdit control to display different colors.

1請參照下列步驟:
To try this example, do the following steps:

在一個已存在的應用新增一個對話方塊,參見《dialog editor in the Visual C++ User’s Guide》。

您必須有一個已存在的應用程式來開發可重用控制元件,如果您還沒有可使用的應用程式,您不妨使用 AppWizard 來建立一個基於對話方塊的應用程式。
Create a new dialog box in an existing application. For more information seedialog editor in the Visual C++ User’s Guide.
You must have an application in which to develop the reusable control. If you don’t have an existing application to use, create a dialog-based application using AppWizard.

等 VC++ 把您的應用程式載入之後,您使用 ClassWizard 建立一個基於 CEdit 類的新CYellowEdit類。取消 "Add To Component Gallery" 選項。
With your project loaded into Visual C++, use ClassWizard to create a new class called CYellowEdit based on CEdit. Leave the “Add to Component Gallery” box checked.

在 CYellowEdit 類中新增三個成員變數。前兩個是 COLORREF 的變數以記錄文字和背景顏色。第三個變數是一個用於繪製背景的刷子類 CBrush 變數。刷子變數允許你只建立一次,接下來只要引用它即可,一直到 CYellowEdit 控制元件銷燬的時候刷子才被自動銷燬。
Add three member variables to your CYellowEdit class. The first two will be COLORREF variables to hold the text color and the background color. The third will be a CBrush object which will hold the brush for painting the background. The CBrush object allows you to create the brush once, merely referencing it after that, and to destroy the brush automatically when the CYellowEdit control is destroyed.

在建構函式中初始化這些成員變數:
Initialize the member variables by writing the constructor as follows:
CYellowEdit::CYellowEdit()
{
 m_clrText = RGB( 0, 0, 0 );
 m_clrBkgnd = RGB( 255, 255, 0 );
 m_brBkgnd.CreateSolirush( m_clrBkgnd );
}

使用 ClassWizard 給您的 CYellowEdit 類為 WM_CTLCOLOR 反射訊息新增一個處理函式。注意,您能處理的訊息列表中的訊息名稱前的等於號表明該訊息是個可以被反射的訊息。這在《Defining a Message Handler for a Reflected Message in the Visual C++ Programmer's Guide》中有所描述。ClassWizard 會為您新增下面的訊息對映宏以及相應的函式骨架:

Using ClassWizard, add a handler for the reflected WM_CTLCOLOR message to your CYellowEdit class. Note that the equal sign in front of the message name in the list of messages you can handle indicates that the message is reflected. This is described inDefining a Message Handler for a Reflected Message in the Visual C++ Programmer's Guide.
ClassWizard adds the following message-map macro and skeleton function for you:

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;
}

用下面的程式碼代替函式的主體。該程式程式碼很簡單,就是指定文字顏色、文字背景顏色以及控制元件其餘部分的背景顏色。
Replace the body of the function with the following code. The code specifies the text color, the text background color, and the background color for rest of the control.
pDC->SetTextColor( m_clrText );  // text
pDC->SetBkColor( m_clrBkgnd );  // text bkgnd
return m_brBkgnd;  // ctl bkgnd

在對話方塊中建立一個編輯控制元件,按下一個控制元件鍵下之後雙擊編輯控制元件並使之與一個成員變數相關聯。在為對話方塊增添成員變數之際,完成變數名稱,並在“控制元件”中選擇“CYellowEdit”作為您的變數原型。別忘記在你的對話方塊中設定 Tab 順序。另外也別忘記在你的對話方塊頭中新增 CYellowEdit 類的標頭檔案。

Create an edit control in your dialog box, then attach it to a member variable by double-clicking the edit control while holding a control key down. In the Add Member Variable dialog box, finish the variable name and choose “Control” for the category, then “CYellowEdit” for the variable type. Don’t forget to set the tab order in the dialog box. Also, be sure to include the header file for the CYellowEdit control in your dialog box’s header file.

編譯並執行您的程式,該編輯控制元件將顯示一個黃色的背景。
Build and run your application. The edit control will have a yellow background.

現在您可以使用 Component Gallery 把您的 CYellowEdit 控制元件類新增到其他工程專案中去。

You can now use Component Gallery to add your CYellowEdit control class to other projects.


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990328/,如需轉載,請註明出處,否則將追究法律責任。

相關文章