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