如何有效地判断鼠标是否位于顶层窗口?如何判断鼠标是否位于顶层窗口?
“over”是指鼠标指针位于顶级窗口和的客户端矩形内,鼠标指针位置处没有其他顶层窗口。换句话说,如果用户点击该事件将被发送到我的顶级窗口(或其子窗口之一)。
我正在使用Windows Forms编写C#,但我不介意使用p/invoke来进行Win32调用。
如何有效地判断鼠标是否位于顶层窗口?如何判断鼠标是否位于顶层窗口?
“over”是指鼠标指针位于顶级窗口和的客户端矩形内,鼠标指针位置处没有其他顶层窗口。换句话说,如果用户点击该事件将被发送到我的顶级窗口(或其子窗口之一)。
我正在使用Windows Forms编写C#,但我不介意使用p/invoke来进行Win32调用。
您可以使用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);
一旦你发现没有父窗口,该窗口将是一个顶层窗口。由于您最初传入的点属于未被另一个窗口覆盖的控件,因此顶层窗口必定是该点所属的窗口。
获得窗口句柄后,可以使用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);
在什么情况下鼠标不在WindowFromPoint返回的窗口内? – 2010-10-10 17:40:07
@Daniel - 当鼠标位于窗口的非客户区时,根据OP的请求。像表单的边框和标题一样。 – 2010-10-10 17:51:31
@Daniel,只是额外的补充,你可以直接使用'GetWindowLongPtr()'来检查它是否是顶层窗口。将'GWL_EXSTYLE'传递给'nIndex'参数,然后对函数结果使用按位运算来检查它是否包含'WS_EX_TOPMOST'值。 – Vantomex 2010-10-11 03:09:17
游标位置可以通过'Control.MousePosition'获得;父窗口可以通过'user32.dll'中的'GetAncestor(hwnd,2)'来找到('GetParent'不仅可以检查父母,也可以检查窗口所有者,这可能不是很好)。 – max 2010-10-10 17:23:53
Coredll.dll仅适用于Windows Mobile。 – 2010-10-10 19:27:23
@Hans:谢谢,我想我错了。更新。 – Timwi 2010-10-10 22:59:03