CCaptionButton - 在标题栏上添加按钮






4.96/5 (21投票s)
2005年9月20日
4分钟阅读

138890

5375
一个可重用的WTL基类,用于在标题栏上添加按钮。
引言
在创建了CAppBar类后,我希望在标题栏上添加一个按钮,紧挨着“关闭”按钮,以控制AppBar窗口的autohide
属性。在标题栏上添加按钮不像在客户区添加普通按钮那么容易。有一些现有的应用程序在标题栏上带有自定义按钮。但我们很难找到实现这些功能的代码(更不用说可重用的代码)了。所以,我决定创建一个。这就是CCaptionButton
。
在标题栏上添加一个普通的基于窗口的按钮是绝对不可能的。那些出现在标题栏上的按钮实际上是用普通按钮的外观和感觉在标题栏上绘制出来的。处理WM_NCPAINT
消息是实现这一目标的主要方法。当然,为了获得真实的按钮外观和感觉,还需要处理鼠标移动等其他消息。
准备图像
由于我们需要在标题栏上绘制按钮,所以需要准备一些图像来模拟按钮。CCaptionButton
类需要一个包含以下图像的图像列表来表示每个按钮:
- 正常状态
- 按下状态
- 悬停状态
- 选中状态(可选)
- 禁用状态(可选)
上面的列表足以让你理解每个状态的含义。下面是创建一个用于我们的图钉标题按钮的图像列表的示例图像:
添加标题按钮
我们需要为单个窗口支持多个标题按钮。每个按钮在内部以以下数据结构存储:
struct _button { UINT uID; //command ID int cx; //width int cy; //height HIMAGELIST himl; //image list UINT uStatus; //status (image index) char szHint[80]; //tooltip text };
一个向量用于在内部保存按钮。要添加一个按钮,只需调用:
int AddButton(UINT uID, int cx, int cy, HIMAGELIST himl, LPCTSTR lpszHint=NULL);
其中
uID
是按钮的命令ID。当按钮被点击时,一个带有uID
参数的WM_COMMAND
消息将被发送到窗口。因此,处理标题按钮的点击与处理普通按钮的点击方式相同。cx
和cy
指定按钮的大小。此大小必须与相应图像列表中图像的大小匹配。himl
保存绘制按钮所需的所有图像。它必须至少包含三个图像,并且顺序与前面描述的相同;如果需要选中和禁用状态,则最多包含五个图像。lpszHint
是按钮的工具提示文本。
定位
我们在哪里绘制这些按钮?对于一个可重用的类来说,自动定位听起来是必须的。然而,我发现要将按钮放置在所有窗口样式中的正确位置是不可能的。
- 窗口是否是工具窗口,它有一个相对较窄的标题栏?
- 窗口是否包含最小化按钮?
- 窗口是否包含最大化按钮?
- 窗口是否包含帮助按钮?
- …
所有这些都会使自动定位变得混乱。最后,我决定让派生类来定位按钮。GetButtonPos
函数被设计为可被重写,以提供每个按钮的位置。
POINT GetButtonPos(int index);
CCaptionButton
类提供了GetButtonPos
的默认实现。但它假设目标窗口是一个工具窗口,并且没有现有的系统按钮。对于任何其他样式,你必须实现自己的GetButtonPos
来正确地定位按钮。通过提供自定义的GetButtonPos
函数,按钮定位变得比自动定位更强大、更灵活。你甚至可以像在演示应用程序中那样,将两个按钮垂直堆叠。
用法
CCaptionButton
类可以轻松地添加到任何直接或间接派生自CWindowImpl
的ATL/WTL窗口类中。总结使用方法:
- 将
CCaptionButton
类用作基类。 - 使用
CHAIN_MSG_MAP
将消息链接到CCaptionButton
类。 - 调用
AddButton
向标题栏添加一个或多个按钮。 - (重要)重写
GetButtonPos
函数,为每个添加的按钮提供位置。 - 以与处理普通按钮点击相同的方式处理标题按钮点击发送的
WM_COMMAND
通知。 - (可选)调用
CheckButton
来更改标题按钮的选中状态。 - (可选)调用
EnableButton
来更改标题按钮的启用状态。
特点
- 向标题栏添加一个或多个按钮。
- 灵活的定位。
- 支持
WM_COMMAND
处理按钮点击。 - 支持工具提示。
示例应用程序
附带的示例应用程序演示了CCaptionButton
的用法。CAppBar
类也用于AppBar功能。要获取有关CAppBar
的更多详细信息,请在此处查看这里。示例中使用了五个标题按钮。图钉按钮控制AppBar窗口的自动隐藏属性;另外四个按钮将窗口停靠在屏幕的四个边缘;“停靠底部”按钮被禁用,以便你可以看到禁用按钮的外观。
尽情享受吧
好了,代码和示例项目都已附上。我希望它易于使用且代码简洁易懂。我也希望有一天它能成为WTL的一部分。我编写代码时使用的是Visual Studio 2003和WTL7.5。我没有在任何其他平台上进行测试。我希望它能正常工作。如果不行,请给我发消息。我会努力改进它。
中国读者,您可以查看我的博客。本文的中文版本可在此处获取。
修订
- 2005年9月21日 - 修复了经典窗口主题的重绘问题。