激烈振动

Visit My MSN Space

导航

统计

公告

标题栏按钮的WTL实现

起因

上次完成了CAppBar的代码后,就一直想在标题栏的关闭按钮前面加一个按钮,来控制自动隐藏的设置。在标题栏上加按钮并不算特别麻烦,主要是控制WM_NCPAINT,把想要的效果画上去。当然,原理不复杂,要实现的好却不容易。上网搜了一下,有一些简单的例子用来讲述原理,没有找到比较好的实现,更谈不上可复用的代码了,那么只好自己实现了。

原理

首选必须明白原理,想在标题栏上创建CButton这样窗口按钮的努力是徒劳的。标题栏属于Non-Client区域,不能在其上创建子窗口,唯一的方法就是响应WM_NCPAINT消息,通过Window DC画上去,当然,还需要处理一些其他的鼠标消息以得到按钮的效果。这样,实现的思路就和CAppBar差不多了,再创建一个模板类,于是,CCaptionButton<T>就诞生了。 先看看效果

按钮图片

因为是画上去的按钮,我们需要准备一些按钮图片。一个按钮至少需要3个图片来表示3个状态:

  • 正常状态
  • 按下状态
  • 鼠标停留状态
另外,如果需要下面两种额外状态,就需要一共提供5个按钮图片
  • Checked状态
  • Disabled状态

我们通过一个ImageList来组织这些按钮图片。一幅象下面这样的图片资源可以产生一个按钮需要的ImageList,当然也可以通过其他方式实现。

当添加一个标题栏按钮时,我们需要这些按钮图片,参数的类型是HIMAGELIST

添加标题栏按钮

我们需要支持多个标题栏按钮,因此在CCaptionButton类中,通过一个vector来维护所有按钮的信息。具体实现不多说了,就讲怎么使用吧,添加按钮的方法就是:

 int AddButton(UINT uID, int cx, int cy, HIMAGELIST himl, LPCTSTR lpszHint=NULL);

其中,uID是按钮的ID,当按钮被点击时,会有一个WM_COMMAND消息发送给窗口,uID为参数。因此,处理标题栏按钮点击的方法和处理普通按钮完全相同。cx和cy定义了按钮的宽度和高度,这个尺寸必须和按钮图片相符。himl则包含了3-5幅图片,表示按钮不同状态下的样子。最后,lpszHint是按钮的tooltip提示文字。

控制按钮位置

加入的按钮显示在标题栏的什么地方呢?自动控制按钮的位置似乎是一个可重用的类应该完成的任务。在类的实现中,我尝试自动计算标题栏上的空白区域,让我们添加的标题栏按钮靠窗口右边已有按钮排列。然而,我发现,由于存在许多不同的窗口样式,如是否有最小化按钮,是否有问号按钮,是否窄标题栏(即ToolWindow),自动计算很容易产生错误。不如让继承类来决定如何排放按钮位置。因此,提供了下面这个函数供继承类重载:

 POINT GetButtonPos(int index);

CCaptionButton为这个函数提供了一个默认的实现,但是,这个实现比较简单,只有在窗口为ToolWindow,并且没有任何系统按钮的情况下才能正常显示。通过重载GetButtonPos函数,实际上我们得到了比自动计算强的多的功能,即我们可以在任意位置显示按钮,甚至可以控制按钮水平或者垂直排列,就象例子程序中看到的那样。

使用方法

总结一下使用方法

  • 把CCaptionButton作为一个父类继承
  • 使用CHAIN_MSG_MAP把消息传递到CCaptionButton类
  • 调用AddButton函数添加一个或多个按钮
  • 重载GetButtonPos函数提供每个按钮的显示位置
  • 处理标题栏按钮产生的Command消息
  • 可以调用CheckButton改变按钮的Check状态
  • 可以调用EnableButton改变按钮的Enable状态

示例程序

示例程序中使用了5个标题按钮,并配合使用了CAppBar类,以实现桌面停靠的功能。5个标题按钮的排列使用了普通方式和垂直排列的方式,通过继承GetButtonPos函数实现。其中图钉按钮控制AppBar窗口的自动隐藏设置;其他4个按钮使窗口停靠到桌面的一边;并且把停靠到底部的按钮设置成Disabled,可以看到不同的效果

下载示例程序

posted on 2005-09-20 10:45 vibration 阅读(...) 评论(...) 编辑 收藏