DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

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消息返回给控件,以告诉控件它刚才发出了一个什么样的消息,这样控件就能做出相应的处理了,比如再发出事件给包容器。

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

(1)	class CDemoSubclassCtrl : public COleControl
	{
	protected:
		LRESULT OnOcmCommand(WPARAM ,LPARAM) ;
	....
	} ;
	
(2)	BEGIN_MESSAGE_MAP(CDemoSubclassCtrl, COleControL)
		ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
	END_MESSAGE_MAP()
	
(3)	LRESULT CDemoSubclassCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
	{
	#ifdef _WIN32
		WORD wNotifyCode = HIWORD(wParam);
	#else
		WORD wNotifyCode = HIWORD(lParam);
	#endif

		switch (wNotifyCode)
		{
		case BN_CLICKED:
			FireClick() ;	// 一般是发事件给包容器。也可以做别的事情
			break;
		}

		return 0;
	}

同样的方法,也可以处理OCM_CTLCOLORBTN或OCM_DRAWITEM等消息来改变按钮的样貌。
posted on   DoubleLi  阅读(547)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2011-10-26 jQuery学习笔记--JqGrid相关操作 方法列表 备忘 重点讲解(超重要)
点击右上角即可分享
微信分享提示