天天看点

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的处理: