Windows平台提供了丰富的控件,但是在使用中我们不会使用它提供的默认风格,有时候需要对控件进行改写,让它展现出更友好的一面,这次主要是说明三态按钮的实现。
三态按钮指的是按钮在鼠标移到按钮上时显示一种状态,鼠标在按下时展现一种状态,在鼠标移开时又展现出另外一种状态,总共三种。当然鼠标按下和移出按钮展示的状态系统自己提供的有,这个时候在处理这两种状态只需要贴相应的图片就行了,三态按钮的实现关键在于如何判断鼠标已经移动到按钮上以及鼠标移出按钮,然后根据鼠标的位置将按钮做相应的调整。
判断鼠标在按钮的相应位置,系统提供了一个函数_TrackMouseEvent用户处理鼠标移出、移入按钮。函数原型如下:
函数需要传入一个TRACKMOUSEEVENT类型的指针,该结构的原型如下:
在使用该函数时需要包含头文件commctrl.h和lib文件comctl32.lib
解决了鼠标行为的检测之后,就是针对不同的鼠标行为重绘相应的按钮。重绘按钮需要在消息WM_DRAWITEM中,这个消息的处理是在相应控件的父窗口中实现的,而在一般情况下父窗口不会收到该消息,需要我们手工指定控件资源的属性为的OWNERDRAW为真,或者在创建相应的按钮窗口时将样式设置为BS_OWNERDRAW 。
设置完成后就可以在对应的父窗口处理函数中接收并处理WM_DRAWITEM,在该消息中重绘按钮
该消息中主要使用的参数是lpParam它里面包含的是一个指向DRAWITEMSTRUCT的结构体:
而绘制控件时我们可以使用函数DrawFrameControl,该函数可以根据指定的控件类型、控件所处的状态来绘制控件的样式,绘制出来的任然是系统的之前的标准样式,处理WM_DRAWITEN消息的具体代码如下:
函数_TrackMouseEvent根据其检测的鼠标状态不同可以返回不同的消息,这次主要用的是WM_MOUSEHOVER(表示鼠标移动到按钮上)、WM_MOUSELEAVE(鼠标移出按钮),还需要注意的是这个函数每次检测完成返回后不会再次检测,需要我们自己主动调用函数检测鼠标状态,由于要多次调用,而每次调用都需要初始化所需要的结构体指针,所以我们封装一个函数专门用于调用_TrackMouseEvent:
消息WM_MOUSEHOVER和消息WM_MOUSELEAVE的处理是在对应的窗口过程中处理的,而按钮的窗口过程由系统提供我们并不知道,所以只有使用子类化的方法在我们的窗口过程中处理这两个消息。在按钮创建后立马要检测鼠标所以可以按钮对应的父窗口完成创建后子类化,对于窗口可以在它的WM_CREATE消息中处理,对于对话框可以在WM_INITDIALOG消息中处理,子类化调用函数SetWindowLong:
在新的窗口过程中处理消息,完成三态按钮:
到这个地方为止,已经实现了三态按钮的基本样式,通过检测鼠标的位置设置按钮样式,上述代码只是改变了按钮的背景颜色和文字颜色,可能效果不好看。