天天看點

Subclassing a Windows Control

Subclassing一個已有的Windows通用控件,可以減少很多工作量。新的控件可以繼承被subclass的控件的很多能力,如繪制和對滑鼠的響應等。在用MFC ActiveX Control Wizard建立一個工程時,可以選擇Subclass a Windows Control,将生成一些必要的代碼。我們也可以手工向一個已有的ActiveX工程中加入這些代碼: 

一、重載COleControl::IsSubclassedControl、PreCreateWindow 

BOOL CDemoSubclassCtrl::PreCreateWindow(CREATESTRUCT &cs)

{

cs.lpszClass = _T("BUTTON") ; // 辨別從一個BUTTON容器subclass

return COleControl::PreCreateWindow(cs) ;

}

BOOL CDemoSubclassCtrl::IsSubclassedControl()

return TRUE ;

二、修改OnDraw函數,不需要自己繪制了 

void CDemoSubclassCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)

DoSuperclassPaint(pdc, rcBounds);

三、處理Reflected容器消息 

Windows控件一般都是通過向父視窗發消息和從父視窗接受Reflected消息來實作與父視窗通信的。Reflect消息主要目的在于讓控件有機會控制自己的特性,如WM_CTLCOLOR、WM_DRAWITEM等。 

但是ActiveX控件與它的包容器之間的通信機制并不一樣。ActiveX控件通過向包容器發事件和讀取包容器的Ambient屬性來實作和包容器互動的。雖然ActiveX控件也是容器,但它不需要向父視窗發任何消息。事件表面上類似于消息,但内部機制完全不一樣。事件的基礎是連接配接點,而MFC中的消息處理靠的是一條從子類到父類的消息鍊。(具體的可參閱侯捷的《深入淺出MFC》) 

但是當一個ActiveX控件subclass了一個Windows控件後,它就會自動地向它的父視窗發消息,如BN_CLICKED。要想辦法不讓它發消息給包容器。為此,COleControl為這種類型的ActiveX控件生成了一個額外的父視窗,名為"reflector",大小和位置與控件一樣。當它接受到控件發出的消息後,它會再發一個reflector消息傳回給控件,以告訴控件它剛才發出了一個什麼樣的消息,這樣控件就能做出相應的處理了,比如再發出事件給包容器。

<col>

Message sent by the control

Message reflected to the control

WM_COMMAND

OCM_COMMAND

WM_CTLCOLORBTN

OCM_CTLCOLORBTN

WM_CTLCOLOREDIT

OCM_CTLCOLOREDIT

WM_CTLCOLORDLG

OCM_CTLCOLORDLG

WM_CTLCOLORLISTBOX

OCM_CTLCOLORLISTBOX

WM_CTLCOLORSCROLLBAR

OCM_CTLCOLORSCROLLBAR

WM_CTLCOLORSTATIC

OCM_CTLCOLORSTATIC

WM_CTLCOLOR

OCM_CTLCOLOR

WM_DRAWITEM

OCM_DRAWITEM

WM_MEASUREITEM

OCM_MEASUREITEM

WM_DELETEITEM

OCM_DELETEITEM

WM_VKEYTOITEM

OCM_VKEYTOITEM

WM_CHARTOITEM

OCM_CHARTOITEM

WM_COMPAREITEM

OCM_COMPAREITEM

WM_HSCROLL

OCM_HSCROLL

WM_VSCROLL

OCM_VSCROLL

WM_PARENTNOTIFY

OCM_PARENTNOTIFY

WM_NOTIFY

OCM_NOTIFY

需要手工加入對reflected message的處理: