我正在处理TrackMouseEvent
,WM_MOUSEHOVER
和WM_MOUSELEAVE
的鼠标悬停/离开事件。
唯一的问题是,当鼠标悬停在窗口的任何子项上时,它将向跟踪鼠标的窗口发送WM_MOUSELEAVE
消息。
我实际上了解Windows为什么这样做,但不知道如何解决。谷歌搜索并没有帮助我。我相信解决方案非常简单,我只是错过了一些东西。我正在开发Visual C ++ Win32应用程序。 (没有MFC等)
我的代码:
void TrackMouse(HWND hwnd)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 1; //How long the mouse has to be in the window to trigger a hover event.
tme.hwndTrack = hwnd;
TrackMouseEvent(&tme);
}
WndProc:
case WM_MOUSEMOVE:
{
if (!isTracking)
{
TrackMouse(hWnd);
isTracking = true;
}
break;
}
case WM_MOUSEHOVER:
ShowWindow(MouseIsOver, TRUE);
break;
case WM_MOUSELEAVE:
ShowWindow(MouseIsOver, FALSE);
isTracking = false;
break;
答案 0 :(得分:2)
您的消息处理程序收到一条WM_MOUSELEAVE
消息,告诉它跟踪已完成。您必须再次致电TrackMouseEvent()
才能继续跟踪。没什么要修复的。您的消息处理程序可以采取相应的措施。
没有该消息,您的程序将不了解情况。
答案 1 :(得分:1)
通过在鼠标离开事件上获取鼠标坐标来解决。解决方案不是我想要的那样美丽。
答案 2 :(得分:1)
好的,因此,基于OP实际上可能希望在光标经过跟踪鼠标的窗口的子窗口上方时忽略WM_MOUSELEAVE
的情况,我认为他现在可能正在这样做像这样的东西:
BOOL DidMouseLeaveWindow (HWND hWnd)
{
DWORD msgpos = GetMessagePos ();
POINT pt = { GET_X_LPARAM (msgpos), GET_Y_LPARAM (msgpos) };
ScreenToClient (hWnd, &pt);
RECT cr;
GetClientRect (hWnd, &cr);
return !PtInRect (&cr, pt);
}
对我来说似乎很好。
如果您出于某种原因不喜欢它,也可以这样做:
BOOL DidMouseLeaveWindow (HWND hWnd)
{
DWORD msgpos = GetMessagePos ();
POINT pt = { GET_X_LPARAM (msgpos), GET_Y_LPARAM (msgpos) };
HWND hWndUnderCursor = WindowFromPoint (pt);
return !IsChild (hWnd, hWndUnderCursor);
}
也许更优雅。
这两种方法都存在两个问题。如果(例如)子窗口的右边缘与父窗口的右边缘完全对齐,并且您通过该边缘退出,那么父窗口将永远不会得到其WM_MOUSELEAVE
。如果将光标置于子窗口上方,然后很快将其移出父窗口,则可能会错过
要解决这些问题,建议您将计时器设置为后台。因此,您将执行以下操作:
void TrackMouse(HWND hwnd)
{
// ...
SetTimer (hWnd, 1, 250, 0);
}
在WndProc中:
case WM_TIMER:
case WM_MOUSELEAVE:
if (DidMouseLeaveWindow (hWnd))
{
// ...
isTracking = false;
KillTimer (hWnd, 1);
}
break;
如果TrackMouseEvent
有一个TME_IGNORE_CHILDREN
标志,那很好,但遗憾的是没有。