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