按住鼠标左键时不生成WM_MOUSELEAVE

时间:2010-02-17 18:40:44

标签: c++ winapi mouse

在我的Win32应用程序中,当我按住鼠标左键并快速将鼠标指针移出窗口时,我没有收到WM_MOUSELEAVE消息。但是,如果我按住鼠标左键,从窗口内部开始并缓慢移动通过窗口边缘,它将生成WM_MOUSELEAVE。

如果我没有按住鼠标左键,无论鼠标指针移出窗口多快,我每次都会收到WM_MOUSELEAVE消息。

有什么区别?我能做些什么来妥善处理这两种情况?

编辑:如果我左键单击并按住,移出窗口然后松开鼠标左键我收到WM_MOUSELEAVE消息。但现在为时已晚。

3 个答案:

答案 0 :(得分:5)

在Windows 7上,我试图制作一个所有者绘制的按钮。为了获得更精确的mouseenter / mouseleave事件,我将按钮子类化了。当我这样做时,我在获得WM_MOUSEMOVE时使用了TrackMouseEvent,因为只有当鼠标悬停在按钮上时才会发布。如果还没有设置,我会设置一个布尔值来指定鼠标位于按钮上方以及调用TrackMouseEvent,这样只要鼠标离开,我就可以取消设置我的布尔值。然而,就像你一样,当我按下并按住所有者绘制按钮上的鼠标左键,然后将鼠标拖出时,我没有得到WM_MOUSELEAVE。将鼠标放在按钮外面时,我突然收到WM_MOUSELEAVE消息 - 太迟了。

我确定这种行为的原因是默认按钮proc对WM_LBUTTONDOWN的处理调用了SetCapture,并在以后发布。 SetCapture的使用正在打破我们对WM_MOUSELEAVE事件的接收。但是,作为调用SetCapture的副作用,即使控件不在鼠标下,我们也会得到WM_MOUSEMOVE事件。因此,我的解决方法是复制WM_MOUSEMOVE处理程序中WM_MOUSELEAVE中的逻辑,以取消设置我的布尔值,指示如果我的按钮区域之外的mousemove事件,则鼠标位于按钮上方。如果在WM_LBUTTONDOWN中实际上没有使用SetCapture作为默认按钮proc,那么我们已经收到了WM_MOUSELEAVE消息,代码仍然可以工作......所以这种解决方法在两种情况下都有效。

你的问题听起来可能与我的问题相同,所以希望这会对你有所帮助。

答案 1 :(得分:3)

WM_MOUSELEAVE是为了在捕获时可以检测到离开窗口的鼠标。捕获后,您有责任自行检测(如果您关心)。

所以SetCaptureTrackMouseEvent同时没有任何意义,你会使用其中一个。

现在,如果你在捕获时看到WM_MOUSELEAVE消息会更方便,那么在你的消息泵中自己做这件事就相对简单了。

您只需在消息泵中的GetMessage()DispatchMessage()来电之间添加看起来像这样的代码。

  GetMessage(pmsg, ...);

  .....

  if ((IS_WITHIN(pmsg->message, WM_MOUSEFIRST, WM_MOUSELAST) ||
       IS_WITHIN(pmsg->message, WM_NCMOUSEMOVE, WM_NCMBUTTONDBLCLK)) &&
       MyMouseLeaveDetection(pmsg, g_hwndNotifyMouseLeave))
     {
     MSG msg = *pmsg;
     msg.message = WM_MOUSELEAVE;
     msg.hwnd    = g_hwndNotifyMouseLeave; // window that want's 
     msg.lParam  = 0xFFFFFFFF;
     g_hwndNotifyMouseLeave = NULL;

     DispatchMessage (&msg);
     }

 .....
 TranslateMessage(pmsg);
 DispatchMessage(pmsg);

答案 2 :(得分:-1)

由于等待WM_MOUSELEAVE不可靠,我发现的最佳解决方案是在WM_MOUSEMOVE期间直接查看鼠标位置。我将鼠标位置与客户区域进行比较,如果位置在外面,那么我会在鼠标离开时处理它。

我还确保当鼠标位置在客户区域内时调用SetCapture,并在离开时调用ReleaseCapture。