使用 WTL 的 CBitmapButton






4.67/5 (3投票s)
2002年4月1日
5分钟阅读

125911

4436
如何使用 Windows Template Library CBitmapButton。
引言
本文介绍如何使用 WTL 中的位图按钮模板。您可以使用 AtlCtrlx.h 中提供的 `CBitmapButton` 类,或者我们的小型辅助类 `CBmpBtn`,它直接使用模板并修复了我们遇到的一个图像刷新问题。辅助类的源代码可从上面的链接获取,并在示例项目中使用。
按钮图像
CodeProject.com 和其他地方有很多关于在按钮上绘制图像的出色文章。除了本文稍后进行的讨论外,我们将引导您参考其他资源。
按钮样式
`CBitmapButtonImpl` 默认仅设置 `BMPBTN_AUTOSIZE` 样式。自动大小会调整按钮的大小以适应您提供的图像。`CBmpBtn`,示例项目中的辅助类,在按钮构造函数中将 `BMPBTN_AUTO3D_SINGLE` 添加到扩展样式中,以便在按钮图像周围绘制 3D 边框。
示例项目中还有一个方法,当复选框被单击时设置悬停按钮样式。这允许您查看有和没有悬停样式的效果。对于常规程序,您只需将 `BMPBTN_HOVER` 样式添加到按钮构造函数中。
也可以使用 `SetBitmapButtonExtendedStyle()` 设置按钮样式。其他样式,其中一些将在本文稍后讨论,包括:
BMPBTN_AUTO3D_DOUBLE
-- 绘制双按钮边框,类似于“经典”Windows 按钮BMPBTN_AUTOFIRE
-- 当按下自动开火按钮时,它会重复单击按钮的消息,直到释放按钮。BMPBTN_SHAREIMAGELISTS
-- 指示按钮的内部图像列表与其他按钮共享
使用 CBitmapButton
`CBitmapButtonImpl` 模板在两个方面与众不同。首先,它使用 `SubclassWindow` 将其附加到按钮对象,而不是像大多数 WTL 控件那样进行简单的赋值。其次,除非您在子类化之前先创建并为一个按钮分配一个图像列表和至少一个图像,否则它会在调试版本中产生多个断言。
同样重要的是要注意,`CBitmapButtonImpl` 是一个“纯”位图按钮,不执行任何 Windows 文本处理。您必须在提供的图像中绘制文本。有关示例,请参阅本文后面的“如何制作按钮图像”部分。
在示例项目中,OK 按钮的 `CImageList` 成员变量用于保存其他按钮的图像。图像列表在 `OnInitDialog` 处理程序中创建,如下所示:
CBmpBtn m_ok; CBmpBtn m_cancel; LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { // change button style for the OK button DWORD dw = BMPBTN_SHAREIMAGELISTS | BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTOSIZE; m_ok.SetBitmapButtonExtendedStyle(dw); // create the OK button's imagelist. Use a light gray mask m_ok.m_ImageList.Create(IDB_BUTTONS, 64, 0, RGB(192,192,192)); ...
创建图像列表后,需要将其分配给按钮。以下代码,接续上面的初始化对话框处理程序,展示了子类化示例对话框的 OK 按钮,然后为 Cancel 按钮使用共享图像列表的步骤。一个按钮至少需要一个图像,最多可以有四个图像来处理不同的按钮状态。
// get the OK button's imagelist handle for use with other buttons HIMAGELIST hImage = m_ok.GetImageList(); // OK button: set images, subclass m_ok.SetImages(0, 1, 2, 3); m_ok.SubclassWindow(GetDlgItem(IDOK)); // Cancel button: assign imagelist, set images, subclass m_cancel.SetImageList(hImage); // imagelist handle from OK button m_cancel.SetImages(4, 5, 6, 7); m_cancel.SubclassWindow(GetDlgItem(IDCANCEL));
请记住在程序结束时销毁图像列表。对话框的 `OnDestroy()` 处理程序是一个好地方,如下所示:
LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL&) { // destroy OK button imagelist m_ok.m_ImageList.Destroy(); return 0; }
图像伪影
使用模板提供的 `DoPaint()` 消息时,按钮图像以一种非常惊人的方式叠加在一起。为了纠正这一点,我们添加了背景填充并调用继承的方法来处理其余部分:
// override of CBitmapButtonImpl DoPaint() in CBmpBtn class void DoPaint(CDCHandle dc) { RECT rc; GetClientRect(&rc); dc.FillRect(&rc, (HBRUSH)(COLOR_BTNFACE+1)); // call inherited DoPaint() CBitmapButtonImpl<CBmpBtn>::DoPaint(dc); }
请注意,我们在此处使用 `FillRect()` 来基本上“涂抹”掉前一个按钮状态。您可能会考虑改用 `FloodFill()`,但我们发现 `FloodFill()` 比 `FillRect()` 慢很多,并且会导致按钮操作迟缓。
自动开火按钮
位图按钮模板提供了一个自动开火样式。当按下自动开火按钮超过计时器间隔时,它会发送多个 `BN_CLICKED` 命令,直到释放按钮。示例项目展示了如何处理单击消息并使用它们来递增 `CProgressBarCtrl`。在用户需要执行多次按钮单击的任何情况下,自动开火按钮都很有用。
如何制作按钮图像
每个位图按钮至少需要一个图像,最多可以有四个。图像代表按钮的正常、按下、悬停和禁用状态。如果您只提供一个图像,它将用于所有四种状态。有关使用单个图像的示例,请参阅自动开火按钮。
以下图像用于示例项目的 OK 按钮。图像的每个四分之一(1/4)部分服务于四种按钮状态中的一种。每个段的宽度为 64 像素,略窄于“经典”按钮,高度为 24 像素。
要制作正常状态图像,请使用图像编辑器用蒙版颜色填充背景,添加所需的任何图片,然后放置文本。按下状态图像填充有交叉的背景,即交替的灰色和白色点,其上方放置与正常状态相同的图片和文本。`CBitmapButton` 将图像偏移一像素向上和一像素向下,以完成“按下”外观。
制作悬停图像很简单。从正常图像的副本开始,并将图像轮廓颜色和文本颜色更改为您首选的悬停颜色。我们使用中蓝色而不是传统的深蓝色,以便悬停(以及非悬停样式下的焦点)能够清晰地显示出来。
最终状态,禁用状态,也从正常状态的副本开始。但是,您必须:1)将图像中的任何颜色灰色化;2)将图片轮廓和文本颜色更改为深灰色;3)在每个图片和字母的右侧和底部绘制白色阴影。
使用条款
本文提供的示例项目和位图按钮类是免费的。您可以随意使用它们。
本软件按“现状”分发,不提供任何形式的担保。