【问题标题】:WM_MOUSELEAVE not being generated when left mouse button is held按住鼠标左键时未生成 WM_MOUSELEAVE
【发布时间】:2010-02-17 18:40:44
【问题描述】:

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

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

有什么区别?我该怎么做才能正确处理这两种情况?

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

【问题讨论】:

  • 你什么时候打电话给TrackMouseEvent?会不会是您遇到了延迟,并且您设法在调用 TrackMouseEvent 之前离开窗口?
  • 每当客户区有鼠标移动时,我都会执行 TrackMouseEvent。

标签: c++ winapi mouse


【解决方案1】:

在 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 事件,则表示鼠标位于按钮上方。如果 SetCapture 实际上没有在 WM_LBUTTONDOWN 中用于默认按钮 proc,那么我们将已经收到 WM_MOUSELEAVE 消息并且代码仍然可以工作......所以这个解决方法在这两种情况下都有效。

您的问题听起来可能与我的相同,因此希望这对您有所帮助。

【讨论】:

    【解决方案2】:

    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);
    

    【讨论】:

      【解决方案3】:

      由于等待 WM_MOUSELEAVE 是不可靠的,我发现的最佳解决方案是在 WM_MOUSEMOVE 期间直接查看鼠标位置。我将鼠标位置与客户区进行比较,如果位置在外部,则将其作为鼠标离开来处理。

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

      【讨论】:

      • 请记住,当用户在您的窗口中按下鼠标按钮时,SetCapture 起作用。您是否尝试同时使用 SetCapture 和 TrackMouseEvent?这可以解释你所看到的......
      • 这不是答案!这是一个黑客。答案是投票最多的。
      猜你喜欢
      • 1970-01-01
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多