创建一个ActiveX按钮从MFC所有者绘制按钮

下载demo project - 70.3 KB

介绍

有许多使用c++和MFC类编写的自绘制按钮。还有许多ActiveX控件,大部分是用Visual Basic编写的。在c++中,您可以轻松地使用MFC和OCX控件,而在Visual Basic中,您需要将MFC对象转换为ActiveX控件。不幸的是,类向导没有涵盖发送到ActiveX控件的所有消息和事件,而且有些消息是不同的,因此大部分魔法必须是手写的。

因为有时候,一段代码比本文本身更清晰,所以我包含了将CxShadeButton移植到ActiveX控件的内容,但这只是一个示例。在本文中,我将讨论通用的AxButtonCtrl。

MFC Activex控制向导&类向导

只需点击几下,ActiveX控件向导就会为我们编写大约600行注释代码,这些代码我们可能永远都不会读到。只要记住在组合框中选择“BUTTON”,向导会问:“如果有的话,这个控件应该是哪个窗口类?”,框架就准备好了。

使用类向导,您可以添加成员函数来处理基本消息:

wm_create wm_erasebkgnd wm_keydown wm_lbuttondown wm_mousemove wm_size presubclasswindow

其中一些消息是可选的,但我考虑自定义控件,这样就有很好的机会处理比普通按钮更多的消息。
WM_DRAWITEM消息不在列表中,这不是错误,稍后我将对此进行解释。

PreSubclassWindow

隐藏,复制Codevoid AxuttonCtrl::PreSubclassWindow()
{
… //custom style initialization code
COleControl::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW|BS_NOTIFY);
}

在此方法中,您可以复制在MFC控件中使用的相同代码;区别在于最后两行:按钮现在派生自COleControl(代替了CButton)。你必须设置BS_OWNERDRAW风格与你的自定义图形绘制按钮,和BS_NOTIFY风格,如果你需要一些特殊的通知消息,如BN_DISABLE, BN_KILLFOCUS,…

WM_CREATE,弹出式

这些消息有时不被MFC控件使用,但在Visual Basic中,所见即所得原则要求开发人员在构建GUI时可以看到外观。
控件接收WM_CREATE消息并创建对象与COleControl::OnCreate(lpCreateStruct),在此调用按钮存在后,你可以使用所有的windows函数(CWnd成员在MFC)初始化图形对象。
WM_SIZE消息发送后,WM_CREATE,和当按钮大小已经改变;在这里,您必须构建(或重新构建)图形对象的位置和/或尺寸。

键盘,鼠标消息

这些消息对于工具提示和悬停功能非常有用,请稍后查看。

绘制按钮反射窗口消息

类向导为绘图函数提供了一个AxButtonCtrl::OnDraw成员。

隐藏,复制Codevoid AxButtonCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
DoSuperclassPaint(pdc, rcBounds);
}

你可以让它保持原样。我们的按钮等待WM_DRAWITEM消息,但与activex控件的机制略有不同:COleControl创建一个额外的窗口称为“reflector”,在相同的位置的控制窗口。反射器拦截某些窗口消息,并将它们以不同的名称发送到控件。反映的消息有:

由控制消息发送的消息反映控制wm_command ocm_command 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_notify ocm_notify wm_parentnotify ocm_parentnotify

对于这些消息,您必须手动添加消息处理程序:在控制类.H文件中,声明一个处理程序函数,如下所示:

隐藏,复制Codeclass AxButtonCtrl : public COleControl
{

protected:
LRESULT OnOcmCommand(WPARAM wParam, LPARAM lParam);
LRESULT OnOcmDrawItem(WPARAM wParam, LPARAM lParam);

}

在控件类.CPP文件中,将ON_MESSAGE条目添加到消息映射中:

隐藏,复制CodeBEGIN_MESSAGE_MAP(AxButtonCtrl, COleControl)
//{{AFX_MSG_MAP(AxButtonCtrl)

ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
ON_MESSAGE(OCM_DRAWITEM, OnOcmDrawItem)

//}}AFX_MSG_MAP
END_MESSAGE_MAP()

并实现处理反射消息的成员函数。wParam和lParam参数与原始窗口消息的参数相同。

隐藏,复制CodeLRESULT AxButtonCtrl::OnOcmDrawItem(WPARAM wParam, LPARAM lParam)
{
UINT nIDCtl = (UINT) wParam;
LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT) lParam;
… //drawing code as used in WM_DRAWITEM
return 0;
}

事件

类向导为标准事件提供了一些股票处理程序,但是产生的功能可能是有限的。如果您用stock处理程序实现添加了“Click”事件,那么当有人用鼠标单击按钮时,COleButton会自动调用FireClick方法,因此您不需要处理OCM_COMMAND消息。但是如果按钮有焦点并且有人按下了空格键,尽管按钮通过OCM_COMMAND消息接收到BN_CLICKED通知,但FireClick方法不会被调用。

最后,使用自定义事件处理程序实现,通过这种方式,您可以精确地控制按钮的行为,而不需要隐藏调用或消息。

隐藏,复制CodeLRESULT AxButtonCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
{

...
switch (wNotifyCode)
{
case BN_CLICKED:
	// Fire click event when button is clicked
	FireClick();
	break;
case BN_KILLFOCUS:
...

}
return 0;

}

工具提示

MSDN文章Q141871(如何:向ActiveX控件添加工具提示)也描述了实现的步骤ltips。简历:添加RelayEvent方法和CToolTipCtrl m_ttip成员变量;创建并激活工具提示;在WM_LBUTTONDOWN的处理程序中,WM_LBUTTONUP和WM_MOUSEMOVE调用RelayEvent来将适当的消息传递给工具提示控件。

悬停功能

你必须使用bool m_tracking成员变量来跟踪鼠标位置。当鼠标在按钮上时,WM_MOUSEMOVE消息被发送,并在这里激活跟踪。

隐藏,复制Code…
if (!m_tracking) {
TRACKMOUSEEVENT t = {sizeof(TRACKMOUSEEVENT),TME_LEAVE,m_hWnd,0};
if (::_TrackMouseEvent(&t)) {
m_tracking = true;
Invalidate();
}
}

要检测鼠标何时离开,你必须在控件类.H文件中添加这个消息处理程序:

隐藏,复制CodeLRESULT OnMouseLeave(WPARAM, LPARAM);

在控制类.CPP文件中:

隐藏,复制CodeON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)

LRESULT AxButtonCtrl::OnMouseLeave(WPARAM, LPARAM)
{
ASSERT (m_tracking);
m_tracking = false;
Invalidate();
return 0;
}

结论

这篇文章讨论了如何转换所有者绘制按钮在一个ActiveX控件,这只是开始,建立一个完整的控件,我应该谈谈自动化,属性表,等等…,但是这些主题超出了本文的范围。关于COM的详细信息,请阅读这些文章。

许可证

本文没有明确许可连接但可能包含在本文使用条款文本或下载文件本身。如果有疑问,请通过下面的讨论区联系作者。

可以在这里找到作者可能使用的许可证列表。

本文转载于:http://www.diyabc.com/frontweb/news743.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值