c++ - TrackMouseEvent 问题
问题描述
我有一个子类按钮,当鼠标光标悬停在它上面时,我试图突出显示它。但是,我似乎无法使该TrackMouseEvent()
功能正常工作。下面是创建子类的代码:
hBtn = CreateWindow(L"button", L"", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hWnd, HMENU(400), hInst, NULL);
SetWindowSubclass(hBtn[0], subSIproc, 400, 0);
这是子类过程:
LRESULT CALLBACK subSIproc(HWND hButton, UINT iMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRefData){
int HIflag=0;
switch(iMsg)
{
case WM_MOUSEMOVE:
{
TRACKMOUSEEVENT me{};
me.cbSize = sizeof(TRACKMOUSEEVENT);
me.dwFlags = TME_HOVER | TME_LEAVE;
me.hwndTrack = hButton;
me.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&me);
HIflag = 1;
RedrawWindow(hButton, NULL, NULL, RDW_INVALIDATE);
}
case WM_MOUSEHOVER:
{
HIflag = 2;
RedrawWindow(hButton, NULL, NULL, RDW_INVALIDATE);
}
case WM_MOUSELEAVE:
{
TRACKMOUSEEVENT me{};
me.cbSize = sizeof(TRACKMOUSEEVENT);
me.dwFlags = TME_HOVER | TME_LEAVE | TME_CANCEL;
me.hwndTrack = hButton;
me.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&me);
HIflag = 3;
RedrawWindow(hButton, NULL, NULL, RDW_INVALIDATE);
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hButton, &ps);
if(HIflag==0) FillRect(hdc, &ps.rcPaint, CreateSolidBrush(0x007F7F7F));
if(HIflag==1) FillRect(hdc, &ps.rcPaint, CreateSolidBrush(0x00FF0000));
if(HIflag==2) FillRect(hdc, &ps.rcPaint, CreateSolidBrush(0x000000FF));
if(HIflag==3) FillRect(hdc, &ps.rcPaint, CreateSolidBrush(0x0000FF00));
EndPaint(hButton, &ps);
}
}
return DefSubclassProc(hButton, iMsg, wParam, lParam);
}
变量“HIflag”有四个可能的值,以确定正在接收哪些消息,以及何时---'0'(灰色)表示尚未收到消息;'1'(蓝色)表示已WM_MOUSEMOVE
收到;'2'(红色)表示已WM_MOUSEHOVER
收到;'3' 表示已WM_MOUSELEAVE
收到。
这是发生了什么:当我最初运行程序时,按钮是灰色的(没有收到鼠标消息)。按钮保持灰色,直到我将光标移到按钮上。此时,它变为绿色(表示“WM_MOUSELEAVE”)。它应该变成红色(对于“WM_MOUSEHOVER”)并且在我将光标从按钮上移开之前不会变成绿色。无论我将光标移动到哪里,该按钮现在都保持绿色。
有谁知道我做错了什么?
解决方案
您的case
块缺少break
s,因此当WM_MOUSEMOVE
收到代码时,代码将通过代码 for WM_MOUSEHOVER
,然后将通过代码 for WM_MOUSELEAVE
,然后将通过代码 forWM_PAINT
等。所以HIflag
任何时候都将始终为 3跌倒WM_PAINT
发生。
您还泄漏了HBRUSH
返回CreateSolidBrush()
的内容。DeleteObject()
完成使用后,您需要刷子。
但最重要的HIflag
是,它是内部的一个局部变量subSIproc()
,所以当操作系统自己发出时,它总是为0 WM_PAINT
,而不是当它通过时到达。
您需要在每个按钮的基础上存储HIflag
外部subSIproc()
,例如在内部HWND
使用(Get|Set)WindowLongPtr(GWL_USERDATA)
,(Get|Set)Prop()
等。
尝试更多类似的东西:
hBtn = CreateWindow(L"button", L"", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hWnd, HMENU(400), hInst, NULL);
SetProp(hBtn, TEXT("HIflag"), (HANDLE)0);
SetWindowSubclass(hBtn, subSIproc, 400, 0);
...
LRESULT CALLBACK subSIproc(HWND hButton, UINT iMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRefData)
{
switch (iMsg)
{
case WM_NCDESTROY:
{
RemoveProp(hButton, TEXT("HIflag"));
break;
}
case WM_MOUSEMOVE:
{
TRACKMOUSEEVENT me{};
me.cbSize = sizeof(TRACKMOUSEEVENT);
me.dwFlags = TME_HOVER | TME_LEAVE;
me.hwndTrack = hButton;
me.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&me);
SetProp(hButton, TEXT("HIflag"), (HANDLE)1);
InvalidateRect(hButton, NULL, TRUE);
break;
}
case WM_MOUSEHOVER:
{
SetProp(hButton, TEXT("HIflag"), (HANDLE)2);
InvalidateRect(hButton, NULL, TRUE);
break;
}
case WM_MOUSELEAVE:
{
// tracking is cancelled automatically when this message is generated!
SetProp(hButton, TEXT("HIflag"), (HANDLE)3);
InvalidateRect(hButton, NULL, TRUE);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hButton, &ps);
COLORREF color;
switch ( (int) GetProp(hButton, TEXT("HIflag")) ) {
case 1: color = RGB(0x00, 0x00, 0xFF); break;
case 2: color = RGB(0xFF, 0x00, 0x00); break;
case 3: color = RGB(0x00, 0xFF, 0x00); break;
default: color = RGB(0x7F, 0x7F, 0x7F); break;
}
HBRUSH hBrush = CreateSolidBrush(color);
FillRect(hdc, &ps.rcPaint, hBrush);
DeleteObject(hBrush);
EndPaint(hButton, &ps);
return 0;
}
}
return DefSubclassProc(hButton, iMsg, wParam, lParam);
}
话虽如此,另一种为所有者绘制按钮的背景着色的方法是让父窗口处理WM_CTLCOLORBTN
消息,或者至少处理WM_DRAWITEM
消息。这样,父窗口可以将按钮HWND
及其关联的按钮HIFlag
一起存储在某个数组中,而不必跟踪HWND
自身内部的标志。
例如:
Buttons[index].hWnd = CreateWindow(L"button", L"", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 0, 0, hWnd, HMENU(index+1), hInst, NULL);
Buttons[index].HIflag = 0;
SetWindowSubclass(hBtn, subSIproc, index+1, 0);
...
LRESULT CALLBACK ParentWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg)
{
case WM_CTLCOLORBTN:
{
HWND hBtn = (HWND) lParam;
for (int index = 0; index < NumberOfButtons; ++index)
{
if (Buttons[index].hWnd == hBtn)
{
COLORREF color;
switch ( Buttons[index].HIflag ) {
case 1: color = RGB(0x00, 0x00, 0xFF); break;
case 2: color = RGB(0xFF, 0x00, 0x00); break;
case 3: color = RGB(0x00, 0xFF, 0x00); break;
default: color = RGB(0x7F, 0x7F, 0x7F); break;
}
return CreateSolidBrush(color);
}
}
break;
}
// or:
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*) lParam;
COLORREF color;
switch ( Buttons[dis->CtlID-1].HIflag ) {
case 1: color = RGB(0x00, 0x00, 0xFF); break;
case 2: color = RGB(0xFF, 0x00, 0x00); break;
case 3: color = RGB(0x00, 0xFF, 0x00); break;
default: color = RGB(0x7F, 0x7F, 0x7F); break;
}
HBRUSH hBrush = CreateSolidBrush(color);
FillRect(dis->hDC, &(dis->rcItem), hBrush);
DeleteObject(hBrush);
return TRUE;
}
}
return DefWindowProc(hWnd, uiMsg, wParam, lParam);
}
LRESULT CALLBACK subSIproc(HWND hButton, UINT uiMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRefData)
{
switch (uiMsg)
{
case WM_MOUSEMOVE:
{
TRACKMOUSEEVENT me{};
me.cbSize = sizeof(TRACKMOUSEEVENT);
me.dwFlags = TME_HOVER | TME_LEAVE;
me.hwndTrack = hButton;
me.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&me);
Buttons[uId-1].HIflag = 1;
InvalidateRect(hButton, NULL, TRUE);
break;
}
case WM_MOUSEHOVER:
{
Buttons[uId-1].HIflag = 2;
InvalidateRect(hButton, NULL, TRUE);
break;
}
case WM_MOUSELEAVE:
{
// tracking is cancelled automatically when this message is generated!
Buttons[uId-1].HIflag = 3;
InvalidateRect(hButton, NULL, TRUE);
break;
}
}
return DefSubclassProc(hButton, uiMsg, wParam, lParam);
}
推荐阅读
- python - Airflow XCom - 如何使用 TriggerDagRunOperator 在 DAG 之间共享变量?
- wordpress - 插件嵌入任何文档不向用户显示
- maven - 使用“mvn clean install”命令构建 eclipse che 项目时出现问题
- ios - iOS 中最小部署目标支持的构建大小不同
- javascript - HTML2canvas 屏幕截图不呈现完整的 div,只显示屏幕上可见的内容?
- node.js - 无法窥探原始值;在nestJS中给出未定义
- menu - Medium.com 菜单水平样式 - 参见图片示例
- hibernate - 喜欢 2 列的查询
- ios - 如何从 CVPixelBuffer 创建 CGImage?
- r - 在闪亮的数据库中保存多个用户数据