Избегайте WM_MOUSELEAVE, когда курсор перемещается над дочерним окном - PullRequest
0 голосов
/ 25 июня 2018

Я обрабатываю события при наведении / отпускании мыши с 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;

Ответы [ 3 ]

0 голосов
/ 25 июня 2018

Решено путем получения координат мыши при событии покидания мыши.Решение не так красиво, как я хотел.

0 голосов
/ 26 июня 2018

ОК, поэтому, исходя из того, что ОП (вероятно) хочет, по сути, игнорировать 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, но, к сожалению, это не«т.

0 голосов
/ 25 июня 2018

Ваш обработчик сообщений получает сообщение WM_MOUSELEAVE о том, что отслеживание выполнено.Вы должны позвонить TrackMouseEvent() снова, чтобы продолжить отслеживаниеТам нет ничего, чтобы исправить.Ваш обработчик сообщений может действовать соответственно.

Без этого сообщения ваша программа не будет знать о ситуации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...