SDK平台三态按钮的实现
Windows平台提供了丰富的控件,但是在使用中我们不会使用它提供的默认风格,有时候需要对控件进行改写,让它展现出更友好的一面,这次主要是说明三态按钮的实现。
三态按钮指的是按钮在鼠标移到按钮上时显示一种状态,鼠标在按下时展现一种状态,在鼠标移开时又展现出另外一种状态,总共三种。当然鼠标按下和移出按钮展示的状态系统自己提供的有,这个时候在处理这两种状态只需要贴相应的图片就行了,三态按钮的实现关键在于如何判断鼠标已经移动到按钮上以及鼠标移出按钮,然后根据鼠标的位置将按钮做相应的调整。
判断鼠标在按钮的相应位置,系统提供了一个函数_TrackMouseEvent用户处理鼠标移出、移入按钮。函数原型如下:
BOOL _TrackMouseEvent(
LPTRACKMOUSEEVENT lpEventTrack
);
函数需要传入一个TRACKMOUSEEVENT类型的指针,该结构的原型如下:
typedef struct tagTRACKMOUSEEVENT {
DWORD cbSize;//该结构体所占空间大小
DWORD dwFlags;//指定服务的请求(指定它需要侦听的事件),这次主要用到的是TME_HOVER和TME_LEAVE(侦听鼠标移开和移入事件)
HWND hwndTrack;//指定我们需要侦听的控件的句柄
DWORD dwHoverTime;//HOVER消耗的时间,可以用系统提供的一个常量HOVER_DEFAULT由系统默认给出,也可以自己填写,单位是毫秒
} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;
在使用该函数时需要包含头文件commctrl.h和lib文件comctl32.lib
解决了鼠标行为的检测之后,就是针对不同的鼠标行为重绘相应的按钮。重绘按钮需要在消息WM_DRAWITEM中,这个消息的处理是在相应控件的父窗口中实现的,而在一般情况下父窗口不会收到该消息,需要我们手工指定控件资源的属性为的OWNERDRAW为真,或者在创建相应的按钮窗口时将样式设置为BS_OWNERDRAW 。
设置完成后就可以在对应的父窗口处理函数中接收并处理WM_DRAWITEM,在该消息中重绘按钮
该消息中主要使用的参数是lpParam它里面包含的是一个指向DRAWITEMSTRUCT的结构体:
typedef struct tagDRAWITEMSTRUCT {
UINT CtlType; //控件类型
UINT CtlID; //控件ID
UINT itemID; //子菜单项的ID主要用于菜单
UINT itemAction; //控件发出的动作,如ODA_SELECT表示控件被选中
UINT itemState; //控件状态,这次需要用到的状态为ODS_SELECTED表示按钮被按下
HWND hwndItem; //控件句柄
HDC hDC;
RECT rcItem;//控件的矩形区域
ULONG_PTR itemData;
} DRAWITEMSTRUCT;
//该结构体中的一些成员需要根据控件类型赋值,同时结构体中的itemAction、itemState是可以由多个值通过位或组成在判断是否具有某种状态时需要使用位与运算
而绘制控件时我们可以使用函数DrawFrameControl,该函数可以根据指定的控件类型、控件所处的状态来绘制控件的样式,绘制出来的任然是系统的之前的标准样式,处理WM_DRAWITEN消息的具体代码如下:
LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; char szBuf[50];
GetWindowText(lpdis->hwndItem,szBuf,50);
if (ODT_BUTTON ==lpdis->CtlType)
{
UINT uState = DFCS_BUTTONPUSH;
if (lpdis->itemState & ODS_SELECTED)
{
uState |= DFCS_PUSHED;
} DrawFrameControl(lpdis->hDC,&(lpdis->rcItem),DFC_BUTTON,uState);
SetTextColor(lpdis->hDC,RGB(255,0,0));
DrawText(lpdis->hDC,szBuf,strlen(szBuf) + 1,&(lpdis->rcItem),DT_CENTER |
DT_VCENTER | DT_SINGLELINE);
}
函数_TrackMouseEvent根据其检测的鼠标状态不同可以返回不同的消息,这次主要用的是WM_MOUSEHOVER(表示鼠标移动到按钮上)、WM_MOUSELEAVE(鼠标移出按钮),还需要注意的是这个函数每次检测完成返回后不会再次检测,需要我们自己主动调用函数检测鼠标状态,由于要多次调用,而每次调用都需要初始化所需要的结构体指针,所以我们封装一个函数专门用于调用_TrackMouseEvent:
void Track(HWND hWnd)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 10;
tme.hwndTrack = hWnd;
_TrackMouseEvent(&tme);
}
消息WM_MOUSEHOVER和消息WM_MOUSELEAVE的处理是在对应的窗口过程中处理的,而按钮的窗口过程由系统提供我们并不知道,所以只有使用子类化的方法在我们的窗口过程中处理这两个消息。在按钮创建后立马要检测鼠标所以可以按钮对应的父窗口完成创建后子类化,对于窗口可以在它的WM_CREATE消息中处理,对于对话框可以在WM_INITDIALOG消息中处理,子类化调用函数SetWindowLong:
g_OldProc = (LRESULT*)SetWindowLong(GetDlgItem(hDlg,IDC_BUTTON1),GWL_WNDPROC,(LONG)BtnProc);
return 0;
在新的窗口过程中处理消息,完成三态按钮:
switch (uMsg)
{
case WM_MOUSEMOVE:
Track(hBtn);//当鼠标移动时检测
break;
case WM_MOUSEHOVER:
{
char szBuf[50];
RECT rtBtn;
GetClientRect(hBtn,&rtBtn);
HDC hDc = GetDC(hBtn);
DrawFrameControl(hDc,&(rtBtn),DFC_BUTTON,DFCS_BUTTONPUSH);
HBRUSH hBr = CreateSolidBrush(RGB(255,255,255));
FillRect(hDc,&rtBtn,hBr);
GetWindowText(hBtn,szBuf,50);
SetBkMode(hDc,TRANSPARENT);
DrawText(hDc,szBuf,strlen(szBuf),&rtBtn,DT_CENTER | DT_VCENTER | DT_SINGLELINE);
ReleaseDC(hBtn,hDc);
}
break;
case WM_MOUSELEAVE:
{
char szBuf[50];
RECT rtBtn;
GetClientRect(hBtn,&rtBtn);
HDC hDc = GetDC(hBtn);
DrawFrameControl(hDc,&(rtBtn),DFC_BUTTON,DFCS_BUTTONPUSH);
GetWindowText(hBtn,szBuf,50);
SetBkMode(hDc,TRANSPARENT);//设置字体背景为透明
DrawText(hDc,szBuf,strlen(szBuf),&rtBtn,DT_CENTER | DT_VCENTER | DT_SINGLELINE);
ReleaseDC(hBtn,hDc);
}
break;
default:
return CallWindowProc((WNDPROC)g_OldProc,hBtn,uMsg,wParam, lParam);//在处理完我们感兴趣的消息后一定要记得将按钮的窗口过程还原
}
return 0;
到这个地方为止,已经实现了三态按钮的基本样式,通过检测鼠标的位置设置按钮样式,上述代码只是改变了按钮的背景颜色和文字颜色,可能效果不好看。
SDK平台三态按钮的实现的更多相关文章
- 开发前奏曲之添加Android SDK平台工具
原文:http://android.eoe.cn/topic/android_sdk Android SDK分离不同部位的SDK成单独的下载包.您已经安装只包含SDK工具的SDK入门包.要开发一个An ...
- 【WPF】使用 XAML 的 Trigger 系统实现三态按钮
利用 WPF 的 Trigger 系统,也可以很简单的只使用xmal实现三态按钮.在Window或UserControl的资源中声明按钮的style并加入触发功能.使用的时候直接在button里复写s ...
- kinect学习笔记(二)—— Sdk平台的搭建~、
一.资源下载 由于我们使用的kinect v1.0,所以我们只需要使用1.8版本的sdk就好了,然后资源包,在QQ群的共享里面已经有啦,所以大家可以直接下载. 二.软件安装 ...
- WPF 三态按钮(PNG贴图)
原文 http://blog.csdn.net/power_YQ/article/details/7177183 <Window.Resources> Style x:Key=" ...
- Android 开发工具介绍-SDK工具和平台工具
原文链接:http://android.eoe.cn/topic/android_sdk Android的SDK提供各种工具可以帮你为Android平台开发移动应用程序.这些工具被分类成两组:SDK工 ...
- android sdk 更新那些文件
上篇经验,完成了android开发环境的搭建,相信大家也下载了那1.52G,已经下载好了的Adt_bundle. 那么,我们来点击SDK Manager.exe,看看有些什么吧 2 如图所示,为整个目 ...
- Zedboard(二)使用Vivado+SDK开发嵌入式应用程序——实例一
本次介绍用Vivado构建Zedboard开发板的硬件平台+SDK开发应用程序(Zedboard裸机开发) 过程如下: 一.运行Vivado,建立新工程 指定好工程路径,下一步,选择RTL Proje ...
- Android SDK下载安装及配置教程
2017年12月07日 13:33:32 4942 转载自:http://blog.csdn.net/dr_neo/article/details/49870587 Android开发环境搭建可以分为 ...
- 最新鲜最详细的Android SDK下载安装及配置教程
//来源: http://www.cnblogs.com/summary-2017/p/8073225.html 最近Neo突发神经,想要将学过的一些计算机视觉.机器学习中的算法都放到移动设备上去跑跑 ...
随机推荐
- 怀念的东西:Pirka咖啡,芬兰的味道
怀念的东西:Pirka咖啡,芬兰的味道 前一段收到了小牛同学从芬兰托人寄来的咖啡.拿着提货单的时候,我满脑子问号.这寄货人是谁的呢,我完全没有印象.而且写的是食品.我又想起了最近报道的诈骗消息,给你寄 ...
- maven pom.xml详细介绍,必须留一份
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
- C语言之总结1
1). 终端常用的命令: pwd 显示终端的工作路径. ls list 清单 显示当前工作路径下的所有的文件以及文件夹. ls -l 以详细信息显示当前工作路径下的所有的文件以及文件夹. cd 要切 ...
- ASP.NET MVC 异步Excel数据选择导出
以前习惯用一些框架来实现Excel文件数据导出,工作中也经常用到:比如extJs.easyUI.angularJs等,最近在做mvc程序的时候要实现该功能,相信这种功能在我们实际工作中是很常见,尤其是 ...
- maven之(六)setting.xml的配置文件详解
setting.xml配置文件 maven的配置文件settings.xml存在于两个地方: 1.安装的地方:${M2_HOME}/conf/settings.xml 2.用户的目录:${user.h ...
- jquery插件autoComplete自动弹出
导入 <link rel="stylesheet" href="${ctx }/static/plugins/jQuery-autoComplete-master/ ...
- 替换ubuntu 14.04的源
1. 背景(为什么要替换)安装ubuntu,默认源是(http://extras.ubuntu.com/ubuntu),国内访问很慢...当我们用apt-get安装软件包或者更新时有时很慢,所以才想到 ...
- 开学&东大一周游记
明天就要离开生活但并没有学到多少东西的东大了,不舍,这是真的,因为真的是没学到多少就要走了.但是终归是有收获的,比如感受到了舍长这样的大牛的学习态度,东大的浴池真的很棒,我很感激吉大的伙食诸如此类.感 ...
- NLog在MVC中使用
NLog在MVC中使用 在site根目录新建NLog.config <?xml version="1.0"?> <configuration> <nl ...
- android 音频播放总结 soundlPool,MediaPlay
soundlPool 用于小音频的播放多个同时播放. 使用步骤: 步骤一: 首先下载音频文件可以将其放入assets文件夹下或者res下的raw文件夹下,区别在于assets下可以再新建文件夹二raw ...