如何判断鼠标是否位于顶级窗口之外?

时间:2010-10-10 16:42:52

标签: c# winforms winapi

如何有效地判断鼠标是否在顶级窗口上?

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

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

2 个答案:

答案 0 :(得分:4)

您可以使用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会调用很多东西“windows”:窗口​​内的控件也是“windows”。因此,您可能无法直观地获得顶级窗口(您可能会收到一个单选按钮,面板或其他内容)。您可以迭代地应用GetParent函数来构建GUI层次结构:

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

找到没有父级的窗口后,该窗口将成为顶级窗口。由于您最初传入的点属于另一个窗口未覆盖的控件,因此顶级窗口必然是该点所属的窗口。

答案 1 :(得分: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);