65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.30/5 (7投票s)

2006年8月26日

CPOL

5分钟阅读

viewsIcon

58624

downloadIcon

1685

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

引言

我曾多年考虑创建一个按钮来替代 CBitmapButton
昨天,我克服了懒惰的习惯,开始创建这个按钮。

在我看来,这个按钮比 CBitmapButton 好很多,原因如下:

  1. 只需要一张普通图片。
    其他图片或按钮状态是自动生成的。
    CBitmapButton 需要四张图片:普通、按下、焦点和禁用状态的图片。
  2. 图片背景是透明的。
    透明功能与 CToolBar 相同。
  3. 支持资源位图和图片文件(如位图、GIF、JPG)。
    因此,按钮可以像我们在网站上看到的、色彩丰富的图片一样显示,效果更好。
  4. 支持工具提示。
  5. 一些额外的选项。

以下是资源程序的界面。

中间的 5 个按钮是我的。上面两个使用资源位图 - 背景颜色为灰色。下面三个分别使用位图、GIF 和 JPG 文件 - 背景颜色为黑色。

JPG 文件的背景颜色无法正确传输到 COLOR_BTNFACE - 稍后我会解释原因。
工具提示与每个按钮相关联。如果您运行源代码并在按钮上移动鼠标,您可以在运行时看到它们的工具提示。

禁用按钮

如果您点击右键“启用或禁用”,按钮将被启用/禁用。
禁用按钮的外观如下:

如果您仔细观察上面两个按钮,您可能会发现它们的禁用状态图片略有不同(见下文)。

较弱的立体效果

这是一个有趣的小选项,可以改变按钮边框的立体感,从强到弱。

较强的边框绘制两次,较弱的边框只绘制一次。您可以点击右键“较弱或较强的立体效果”来切换此选项。较弱的边框外观如下:

您能找出上面图片和第一张图片之间的边框差异吗?

XP 使用不同的颜色绘制按钮边框,例如 RGB(241,239,226)、RGB(113,111,100),我只使用黑白颜色 - 简单或懒惰。
XP 操作系统由于其默认对话框颜色,比 95/98/NT 失去了很多 3D 效果。

焦点

如果按钮获得焦点,会在其内部边框上绘制点线。

一个选项允许隐藏点线,这样即使按钮获得焦点也不会绘制这些点线。
您可以尝试点击右键“显示或隐藏焦点”来查看此功能。

我不喜欢焦点线,所以我为自己添加了这个选项 - 世界上还有其他程序员不喜欢焦点边框吗?

禁用策略

一个选项允许以不同方式生成禁用状态的图片。

左侧是正常的 - 就像 Windows 的禁用图片一样,将白色阴影向下和向右移动 1 像素。右侧将白色阴影向上和向左移动 1 像素。

左侧看起来像“凹陷”,右侧看起来像“凸起”。

文件、类、用法和函数

  1. 文件和类

    源代码的“lib”目录下有两个文件:ButtonMine(头文件和源文件)。
    该文件只包含一个类:ButtonMine,它继承自 CButton

  2. 用法
    • 静态方式
      从 VC 的对话框编辑器中向对话框添加一个按钮,然后将按钮样式更改为所有者绘制。
      从 MFC 类向导中为按钮添加一个成员变量。
      转到对话框的头文件,将按钮类型从 CButton 更改为 ButtonMine
      上述步骤与 CBitmapButton 完全相同,所以您已经知道了。
    • 动态方式
      您可以调用 Create() 函数来动态创建按钮。

    昨天,在开发完这个按钮后,我将当前商业应用中的所有图像按钮都从 CBitmapButton 更换成了 ButtonMine,它们完美运行,没有任何问题 - 但所有这些都是静态方式的。

    不幸的是,我还没有尝试过动态创建按钮的方式,因为除了应用程序需求之外,我没有时间做额外的事情。我猜动态方式应该是可以的。

    我花费数小时撰写这篇文章有两个原因:首先,我使用了 CodeProject 下载的几个源代码程序,它们非常有帮助,我提交这篇文章是为了公平交换。其次,我希望为我们的网站带来更多的专业流量,所以,请在阅读本文档或下载我的源代码后,不要忘记访问我们的网站。

  3. 函数
    • 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 日:初始发布
© . All rights reserved.