当光标移到子窗口上时,避免使用WM_MOUSELEAVE

时间:2018-06-25 19:50:56

标签: c++ winapi

我正在处理TrackMouseEventWM_MOUSEHOVERWM_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;

3 个答案:

答案 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标志,那很好,但遗憾的是没有。