用于 MFC 程序的 Super-button, 以替代 CBitmapButton






3.30/5 (7投票s)
用于 MFC 程序的 Super-button,
引言
我曾多年考虑创建一个按钮来替代 CBitmapButton
。
昨天,我克服了懒惰的习惯,开始创建这个按钮。
在我看来,这个按钮比 CBitmapButton
好很多,原因如下:
- 只需要一张普通图片。
其他图片或按钮状态是自动生成的。CBitmapButton
需要四张图片:普通、按下、焦点和禁用状态的图片。 - 图片背景是透明的。
透明功能与CToolBar
相同。 - 支持资源位图和图片文件(如位图、GIF、JPG)。
因此,按钮可以像我们在网站上看到的、色彩丰富的图片一样显示,效果更好。 - 支持工具提示。
- 一些额外的选项。
以下是资源程序的界面。

中间的 5 个按钮是我的。上面两个使用资源位图 - 背景颜色为灰色。下面三个分别使用位图、GIF 和 JPG 文件 - 背景颜色为黑色。
JPG 文件的背景颜色无法正确传输到 COLOR_BTNFACE
- 稍后我会解释原因。
工具提示与每个按钮相关联。如果您运行源代码并在按钮上移动鼠标,您可以在运行时看到它们的工具提示。
禁用按钮
如果您点击右键“启用或禁用”,按钮将被启用/禁用。
禁用按钮的外观如下:

如果您仔细观察上面两个按钮,您可能会发现它们的禁用状态图片略有不同(见下文)。
较弱的立体效果
这是一个有趣的小选项,可以改变按钮边框的立体感,从强到弱。
较强的边框绘制两次,较弱的边框只绘制一次。您可以点击右键“较弱或较强的立体效果”来切换此选项。较弱的边框外观如下:

您能找出上面图片和第一张图片之间的边框差异吗?
XP 使用不同的颜色绘制按钮边框,例如 RGB(241,239,226)、RGB(113,111,100),我只使用黑白颜色 - 简单或懒惰。
XP 操作系统由于其默认对话框颜色,比 95/98/NT 失去了很多 3D 效果。
焦点
如果按钮获得焦点,会在其内部边框上绘制点线。

一个选项允许隐藏点线,这样即使按钮获得焦点也不会绘制这些点线。
您可以尝试点击右键“显示或隐藏焦点”来查看此功能。
我不喜欢焦点线,所以我为自己添加了这个选项 - 世界上还有其他程序员不喜欢焦点边框吗?
禁用策略
一个选项允许以不同方式生成禁用状态的图片。

左侧是正常的 - 就像 Windows 的禁用图片一样,将白色阴影向下和向右移动 1 像素。右侧将白色阴影向上和向左移动 1 像素。
左侧看起来像“凹陷”,右侧看起来像“凸起”。
文件、类、用法和函数
- 文件和类
源代码的“lib”目录下有两个文件:ButtonMine(头文件和源文件)。
该文件只包含一个类:ButtonMine
,它继承自CButton
。 - 用法
- 静态方式
从 VC 的对话框编辑器中向对话框添加一个按钮,然后将按钮样式更改为所有者绘制。
从 MFC 类向导中为按钮添加一个成员变量。
转到对话框的头文件,将按钮类型从CButton
更改为ButtonMine
。
上述步骤与CBitmapButton
完全相同,所以您已经知道了。 - 动态方式
您可以调用Create()
函数来动态创建按钮。
昨天,在开发完这个按钮后,我将当前商业应用中的所有图像按钮都从
CBitmapButton
更换成了ButtonMine
,它们完美运行,没有任何问题 - 但所有这些都是静态方式的。不幸的是,我还没有尝试过动态创建按钮的方式,因为除了应用程序需求之外,我没有时间做额外的事情。我猜动态方式应该是可以的。
我花费数小时撰写这篇文章有两个原因:首先,我使用了 CodeProject 下载的几个源代码程序,它们非常有帮助,我提交这篇文章是为了公平交换。其次,我希望为我们的网站带来更多的专业流量,所以,请在阅读本文档或下载我的源代码后,不要忘记访问我们的网站。
- 静态方式
- 函数
-
BOOL SetImage(int iBmpID,COLORREF clrBkgnd=RGB(192,192,192), BOOL bAutoSize=TRUE,BOOL bNormalDisable=TRUE); BOOL SetImage(LPCSTR pszFile,COLORREF clrBkgnd, BOOL bAutoSize=TRUE,BOOL bNormalDisable=TRUE);
第一个函数从资源加载图像 - 由
iBmpID
标识。
第二个函数从文件加载图像 - 由pszFile
标识。bAutoSize
:如果按钮大小根据图像大小进行调整。bNormalDisable
:禁用图片是“凹陷”(正常)还是“凸起”样式 - 参考上面的图片。
这两个函数可以**随时**调用 - 例如在对话框的构造函数或OnInitDialog()
中。 -
void SetToolTip(LPCSTR pszToolTip);
可选函数,必须在对话框初始化后调用 - 通常在
OnInitDialog()
中调用 - 因为工具提示需要对话框有效的窗口句柄。
还有另外两个版本的SetImage(...)
函数,它们涉及工具提示,因此必须在对话框初始化后调用。 -
void SetWeaker(BOOL bWeaker)
可选函数。
如果bWeaker
为TRUE
(默认为FALSE
),则按钮边框仅绘制一次 - 参考上面的图片。 -
void SetShowFocus(BOOL bShowFocus)
可选函数。
如果bShowFocus
为FALSE
(默认为TRUE
),则不会绘制焦点线 - 参考上面的图片。
-
内部代码
最重要的代码在 SetImage(...)
函数中。
当一个资源位图 ID 或图像文件被传递到函数中时,会创建一个模板缓冲区来读取图像的比特,模板缓冲区在使用完毕后在该函数内部被删除。
有两个永久性图像缓冲区(类成员),一个用于普通图像,另一个用于禁用状态图像。这两个缓冲区比模板缓冲区大 - 换句话说,这两个图像在尺寸上比源图像大 2x2 像素,因为禁用图像需要额外的 1 像素边框来制作白色阴影以实现禁用效果。
这两个缓冲区由内部类 TheBitmap
的实例 bmp_Nml
和 bmp_Dis
持有。
当源图像复制到 bmp_Nml
时,背景颜色被传输到 COLOR_BTNFACE
,这就是为什么按钮图像看起来是透明的原因。
JPG 图片不透明的两个原因:
首先,我不知道如何使用 Photoshop,所以我不知道它的图像文件(img\img.jpg)的背景颜色是否是真正的黑色。
其次,JPG 文件由函数 ::OleLoadPicturePath(...)
加载,谁知道这个函数在里面做什么?如果它真的将 JPG 的黑色传输到位图格式的黑色,那么图像应该是透明的。
历史
- 2006 年 8 月 26 日:初始发布