如何检查Windows窗体中是否真的可以看到窗口?

Tom*_*ski 9 .net c# forms screen winforms

通常,您使用Form.Visible来检查Window是否可见.但有时在屏幕窗口下面是其他窗口,所以它真的看不见.

那么如果窗口真的可见,如何检查c#Windows窗体?

我想完成这个:当我点击键盘上的CTRL + K并且我的窗口在我的屏幕上可见时它什么也没做.但当它在其他窗户下方时,它会弹到顶部(从前面开始).

亲切的问候

小智 6

我通过网络搜索,但是没有找到任何直接的答案,看看窗户的一部分是否真的对用户可见.如果鼠标当前位于窗口可见部分的顶部,我实际上需要一种方法来"测试"表单.我以为我会分享需要几天才能完成的代码:

public class VisibilityTester
{
    private delegate bool CallBackPtr(int hwnd, int lParam);
    private static CallBackPtr callBackPtr;

    /// <summary>
    /// The enumerated pointers of actually visible windows
    /// </summary>
    public static List<IntPtr> enumedwindowPtrs = new List<IntPtr>();
    /// <summary>
    /// The enumerated rectangles of actually visible windows
    /// </summary>
    public static List<Rectangle> enumedwindowRects = new List<Rectangle>();

    /// <summary>
    /// Does a hit test for specified control (is point of control visible to user)
    /// </summary>
    /// <param name="ctrlRect">the rectangle (usually Bounds) of the control</param>
    /// <param name="ctrlHandle">the handle for the control</param>
    /// <param name="p">the point to test (usually MousePosition)</param>
    /// <param name="ExcludeWindow">a control or window to exclude from hit test (means point is visible through this window)</param>
    /// <returns>boolean value indicating if p is visible for ctrlRect</returns>
    public static bool HitTest(Rectangle ctrlRect, IntPtr ctrlHandle, Point p, IntPtr ExcludeWindow)
    {
        // clear results
        enumedwindowPtrs.Clear();
        enumedwindowRects.Clear();

        // Create callback and start enumeration
        callBackPtr = new CallBackPtr(EnumCallBack);
        EnumDesktopWindows(IntPtr.Zero, callBackPtr, 0);

        // Go from last to first window, and substract them from the ctrlRect area
        Region r = new Region(ctrlRect);

        bool StartClipping = false;
        for (int i = enumedwindowRects.Count - 1; i >= 0; i--)
        {
            if (StartClipping && enumedwindowPtrs[i] != ExcludeWindow)
            {
                r.Exclude(enumedwindowRects[i]);
            }

            if (enumedwindowPtrs[i] == ctrlHandle) StartClipping = true;
        }

        // return boolean indicating if point is visible to clipped (truly visible) window
        return r.IsVisible(p);
    }

    /// <summary>
    /// Window enumeration callback
    /// </summary>
    private static bool EnumCallBack(int hwnd, int lParam)
    {
        // If window is visible and not minimized (isiconic)
        if (IsWindow((IntPtr)hwnd) && IsWindowVisible((IntPtr)hwnd) && !IsIconic((IntPtr)hwnd))
        { 
            // add the handle and windowrect to "found windows" collection
            enumedwindowPtrs.Add((IntPtr)hwnd);

            RECT rct;

            if (GetWindowRect((IntPtr)hwnd, out rct))
            {
                // add rect to list
                enumedwindowRects.Add(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top));
            }
            else
            {
                // invalid, make empty rectangle
                enumedwindowRects.Add(new Rectangle(0, 0, 0, 0));
            }
        }

        return true;
    }


    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool IsWindowVisible(IntPtr hWnd);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool IsWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool IsIconic(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern int EnumDesktopWindows(IntPtr hDesktop, CallBackPtr callPtr, int lPar);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left;        // x position of upper-left corner
        public int Top;         // y position of upper-left corner
        public int Right;       // x position of lower-right corner
        public int Bottom;      // y position of lower-right corner

        public override string ToString()
        {
            return Left + "," + Top + "," + Right + "," + Bottom;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


SLa*_*aks 5

您可以调用Activate表单上的方法将其带到前面(如果还没有).

但请注意,如果其他程序处于活动状态,则通常只会闪烁桌面按钮(取决于您从哪里调用).这是Windows 针对焦点窃取标准保护,您不应该尝试解决它.


Nes*_*tor 5

您可以使用 Windows API 枚举所有窗口,检索它们的 Z 顺序并将其与窗口的 Z 顺序进行比较。我想这里已经有人这么做了。