首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
80 阅读
2
nvim番外之将配置的插件管理器更新为lazy
58 阅读
3
2018总结与2019规划
54 阅读
4
PDF标准详解(五)——图形状态
33 阅读
5
为 MariaDB 配置远程访问权限
30 阅读
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
Java
emacs
linux
文本编辑器
elisp
反汇编
OLEDB
数据库编程
数据结构
内核编程
Masimaro
累计撰写
308
篇文章
累计收到
27
条评论
首页
栏目
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
页面
归档
友情链接
关于
搜索到
2
篇与
的结果
2015-11-04
Win32 API 三态按钮的实现
Windows平台提供了丰富的控件,但是在使用中我们不会使用它提供的默认风格,有时候需要对控件进行改写,让它展现出更友好的一面,这次主要是说明三态按钮的实现。三态按钮指的是按钮在鼠标移到按钮上时显示一种状态,鼠标在按下时展现一种状态,在鼠标移开时又展现出另外一种状态,总共三种。当然鼠标按下和移出按钮展示的状态系统自己提供的有,这个时候在处理这两种状态只需要贴相应的图片就行了,三态按钮的实现关键在于如何判断鼠标已经移动到按钮上以及鼠标移出按钮,然后根据鼠标的位置将按钮做相应的调整。判断鼠标在按钮的相应位置,系统提供了一个函数_TrackMouseEvent用户处理鼠标移出、移入按钮。函数原型如下:BOOL _TrackMouseEvent( LPTRACKMOUSEEVENT lpEventTrack );函数需要传入一个TRACKMOUSEEVENT类型的指针,该结构的原型如下:typedef struct tagTRACKMOUSEEVENT { 2 DWORD cbSize;//该结构体所占空间大小 3 DWORD dwFlags;//指定服务的请求(指定它需要侦听的事件),这次主要用到的是TME_HOVER和TME_LEAVE(侦听鼠标移开和移入事件) 4 HWND hwndTrack;//指定我们需要侦听的控件的句柄 5 DWORD dwHoverTime;//HOVER消耗的时间,可以用系统提供的一个常量HOVER_DEFAULT由系统默认给出,也可以自己填写,单位是毫秒 6 } 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)<BR>{ UINTuState = 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); return0; 在新的窗口过程中处理消息,完成三态按钮:switch(uMsg) { caseWM_MOUSEMOVE: Track(hBtn);//当鼠标移动时检测 break; caseWM_MOUSEHOVER: { charszBuf[50]; RECT rtBtn;<BR> GetClientRect(hBtn,&rtBtn); HDChDc = GetDC(hBtn); DrawFrameControl(hDc,&(rtBtn),DFC_BUTTON,DFCS_BUTTONPUSH); HBRUSHhBr = 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; caseWM_MOUSELEAVE: { charszBuf[50]; RECT rtBtn; GetClientRect(hBtn,&rtBtn); HDChDc = 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: returnCallWindowProc((WNDPROC)g_OldProc,hBtn,uMsg,wParam, lParam);//在处理完我们感兴趣的消息后一定要记得将按钮的窗口过程还原 } return0;到这个地方为止,已经实现了三态按钮的基本样式,通过检测鼠标的位置设置按钮样式,上述代码只是改变了按钮的背景颜色和文字颜色,可能效果不好看。
2015年11月04日
4 阅读
0 评论
0 点赞
2015-06-26
Windows程序设计学习笔记(四)自绘控件与贴图的实现
Windows系统提供大量的控件供我们使用,但是系统提供的控件样式都是统一的,不管什么东西看久了自然会厌烦,为了使界面更加美观,添加一些新的东西我们需要自己绘制控件。控件在默认情况下并不进行自绘,如果是在窗口中利用CreateWindow创建的话要在风格中加入一个对应的自绘风格,这个一般在MSDN中都可以查到比如按钮的自绘风格是BS_OWNERDRAW、列表框是 LBS_OWNERDRAWFIXED (列表项的高度一致)、LBS_OWNERDRAWVARIABLE(列表项的高度可以不一致),如果我们是在对话框下通过资源的方式创建的可以在其属性上将自绘风格选上。控件被改为自绘时,每当需要自画时控件都会向其父窗口发送一条WM_DRAWITEM消息,该消息中两个参数的如下:WM_DRAWITEM idCtl = (UINT) wParam; // 控件ID lpdis = (LPDRAWITEMSTRUCT) lParam; // 一个指向DRAWITEMSTRUCT的结构体结构体DRAWITEMSTRUCT的定义如下:typedef struct tagDRAWITEMSTRUCT { UINT CtlType; //控件类型 UINT CtlID; //控件ID UINT itemID; //控件子项的ID只用于菜单项、组合框、列表框 UINT itemAction; //控件行为,一般在一个动态的行为发生时产生 UINT itemState; //控件状态,在处于某个静态时产生 HWND hwndItem; //控件句柄 HDC hDC; //绘制控件的设备上下文句柄 RECT rcItem; //控件项的矩形范围 DWORD itemData; //程序为菜单项、列表项、组合框中的列表项指定的32值 } DRAWITEMSTRUCT; 对于列表框和组合框,在重绘时会发送一条消息:WM_MEASUREITEM,该消息用于设置列表项的大小信息。可以在该消息中利用下面的代码设置行高:LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam; lpmis->itemHeight = 32;下面来说说贴图。贴图的一般步骤为:1)使用LoadBitmap加载一幅图片,该函数的原型为:HBITMAP LoadBitmap(//函数返回一个对应位图的对象句柄 HINSTANCE hInstance, //实例句柄,系统通过这个值找到对应的位图 LPCTSTR lpBitmapName //位图名称,这个值可以通过MAKEINTRESOURCE宏获得 );2)用CreateCompatiableDC函数创建一个与指定DC兼容的内存设备描述符。3)利用SelectObject函数将对应位图选入到对应的HDC中,该函数返回一个原来未被替代的对象句柄,一般我们需要保存这个变量以便以后用于恢复。4)使用BitBlt贴图函数BitBlt,该函数的原型如下:BOOL BitBlt( HDC hdcDest, // 目的控件的设备上下文句柄 int nXDest, // int nYDest, // 这两个参数表示需要贴在目的设备对应矩形中的哪个位置,分别是客户坐标的横坐标和纵坐标 int nWidth, int nHeight, //图片的大小和宽度 HDC hdcSrc, // 源图片所在的DC的句柄 int nXSrc, int nYSrc, //表示从原图片的哪个像素点开始,这两个值表示开始位置的横纵坐标 DWORD dwRop // 贴图的方式,它规定了原图片颜色如何与目标控件颜色组合已形成最终的颜色 );对于第二步的操作并不是必要的,在贴图时我们可以使用同一个句柄作为原和目的句柄,但是当我们需要贴的图片过多,使用同一个句柄会造成客户区的闪烁,所以可以另外定义一个句柄,保存我们所需要的所有图片,然后一次性通过源DC贴到目的DC,这样可以一次完成,避免了客户区的闪烁。下面的例子采用的是ListBox控件:HWND hList = CreateWindow("LISTBOX", "", WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS |WS_VISIBLE | LBS_HASSTRINGS | LBS_NOTIFY | LBS_OWNERDRAWFIXED , 0,0,200,800,hWnd, (HMENU)123, g_hInst, NULL);//在创建ListBox时定义为自画风格,同时WS_CLIPSIBLINGS风格指明在重绘子窗口时不重绘整个客户区在WM_DRAWITEM消息中编写重绘的代码:LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam; RECT rtListItem = lpDis->rcItem; if (ODT_LISTBOX == lpDis->CtlType) { if (ODS_SELECTED & lpDis->itemState)//当某项被选中时设置虚线框并使背景为蓝色 { rtListItem.right -= 2; rtListItem.bottom -= 2; HBRUSH hBlue = CreateSolidBrush(RGB(0,0,255)); HGDIOBJ hOld = SelectObject(lpDis->hDC, hBlue); FillRect(lpDis->hDC, &rtListItem, hBlue); DrawFocusRect(lpDis->hDC, &rtListItem); } //贴图,并将图片背景色设置为所在矩形框的背景色 <span style="white-space:pre"> </span>HBITMAP hBitMap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1)); HDC hMerDc= CreateCompatibleDC(lpDis->hDC); SelectObject(hMerDc, hBitMap); BitBlt(lpDis->hDC, lpDis->rcItem.left, lpDis->rcItem.top, lpDis->rcItem.right - lpDis->rcItem.left, lpDis->rcItem.bottom - lpDis->rcItem.top, hMerDc, 0, 0, SRCAND); SelectObject(lpDis->hDC,hBitMap); DeleteObject(hMerDc); <span style="white-space:pre"> </span>//将文字设置为透明、并显示文字 SetBkMode(lpDis->hDC, TRANSPARENT); DrawText(lpDis->hDC, g_Person[lpDis->itemID].pszName,strlen(g_Person[lpDis->itemID].pszName), &(lpDis->rcItem),DT_CENTER | DT_VCENTER | DT_SINGLELINE); }
2015年06月26日
0 阅读
0 评论
0 点赞