2010-10-10 91 views
4

如何有效地判断鼠标是否位于顶层窗口?如何判断鼠标是否位于顶层窗口?

“over”是指鼠标指针位于顶级窗口的客户端矩形内,鼠标指针位置处没有其他顶层窗口。换句话说,如果用户点击该事件将被发送到我的顶级窗口(或其子窗口之一)。

我正在使用Windows Forms编写C#,但我不介意使用p/invoke来进行Win32调用。

回答

3

您可以使用WinAPI功能WindowFromPoint。它的C#签名是:

[DllImport("user32.dll")] 
static extern IntPtr WindowFromPoint(POINT Point); 

注意POINT这里并不像System.Drawing.Point相同,但提供的PInvoke a declaration for POINT that includes an implicit conversion between the two

如果你不知道的鼠标光标位置,GetCursorPos发现它:

[DllImport("user32.dll")] 
static extern bool GetCursorPos(out POINT lpPoint); 

然而,WinAPI的调用很多事情“窗口”:一个控制窗口内也“窗口”。因此,您可能无法从直观的角度获得顶级窗口(您可能会收到单选按钮,面板或其他内容)。你可以反复适用的GetParent功能走了GUI层次结构:

[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)] 
public static extern IntPtr GetParent(IntPtr hWnd); 

一旦你发现没有父窗口,该窗口将是一个顶层窗口。由于您最初传入的点属于未被另一个窗口覆盖的控件,因此顶层窗口必定是该点所属的窗口。

+0

游标位置可以通过'Control.MousePosition'获得;父窗口可以通过'user32.dll'中的'GetAncestor(hwnd,2)'来找到('GetParent'不仅可以检查父母,也可以检查窗口所有者,这可能不是很好)。 – max 2010-10-10 17:23:53

+0

Coredll.dll仅适用于Windows Mobile。 – 2010-10-10 19:27:23

+0

@Hans:谢谢,我想我错了。更新。 – Timwi 2010-10-10 22:59:03

2

获得窗口句柄后,可以使用Control.FromHandle()获取对该控件的引用。然后检查相对的鼠标位置,看它是否是窗体或控件的客户区域。像这样:

private void timer1_Tick(object sender, EventArgs e) { 
     var hdl = WindowFromPoint(Control.MousePosition); 
     var ctl = Control.FromHandle(hdl); 
     if (ctl != null) { 
      var rel = ctl.PointToClient(Control.MousePosition); 
      if (ctl.ClientRectangle.Contains(rel)) { 
       Console.WriteLine("Found {0}", ctl.Name); 
       return; 
      } 
     } 
     Console.WriteLine("No match"); 
    } 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern IntPtr WindowFromPoint(Point loc); 
+0

在什么情况下鼠标不在WindowFromPoint返回的窗口内? – 2010-10-10 17:40:07

+0

@Daniel - 当鼠标位于窗口的非客户区时,根据OP的请求。像表单的边框和标题一样。 – 2010-10-10 17:51:31

+1

@Daniel,只是额外的补充,你可以直接使用'GetWindowLongPtr()'来检查它是否是顶层窗口。将'GWL_EXSTYLE'传递给'nIndex'参数,然后对函数结果使用按位运算来检查它是否包含'WS_EX_TOPMOST'值。 – Vantomex 2010-10-11 03:09:17

相关问题