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突发神经,想要将学过的一些计算机视觉.机器学习中的算法都放到移动设备上去跑跑 ...
随机推荐
- .NET中的类库
1.object类 所有类都继承于object类,是顶级父类,他有以下成员,都是虚方法: a) ToString() 默认输出对象所属类的全名称(命名空间.类名) b) Equals (O ...
- Java实践 — SSH远程执行Shell脚本(转)
原文地址:http://www.open-open.com/lib/view/open1384351384024.html 1. SSH简介 SSH是Secure Shell的缩写,一 ...
- grunt--自动化打包工具使用
用grunt搭建自动化的web前端开发环境-完整教程 jQuery在使用grunt,bootstrap在使用grunt,百度UEditor在使用grunt,你没有理由不学.不用! 1. 前言 各位we ...
- 妙味H5交互篇备忘
document.addEventListener( 'touchstart', function(e){ e.preventDefault(); } ); 在document上增加touchst ...
- Cstring 的用法
CString位于头文件afx.h中. 这篇文章就来讨论这些技巧. 使用CString可以让你对字符串的操作更加直截了当.这篇文章不是CString的完全手册,但囊括了大部分常见基本问题. 这篇文章包 ...
- MemoryStream和FileStream
一,FileStream对象的数据来自文件,而MemoryStream对象的数据来自内存缓冲区.这两个类都继承自Stream类. 二,抽象基类System.IO.Stream代表流,它提供Read和W ...
- 【转】Oracle + PHP Cookbook(php oracle clob 长度超过4000如何写入)
在甲骨文LOB和PHP工作 由哈里Fuecks 达到4,000字节的限制?输入LOB ... 在这个"Oracle + PHP Cookbook"HowTo中,您将学习可用的L ...
- Smail语法
1.数据类型 2.函数: Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type 注意参数与参数之间没有任何分隔符 3.函数调用: 4.关于s ...
- wpf 线程与界面线程
Thread thread = new Thread(new ThreadStart(() => { VisualTarget visualTarget = ...
- Java 四舍五入并小数点后保存两位,千分位分隔
import java.text.DecimalFormat; public class FileTest { public static void main(String[] args) { ...