15

有没有办法检查 WinForm 在屏幕上是否完全可见(例如没有超出屏幕范围?)

我已经尝试为此使用 SystemInformation.VirtualScreen,只要虚拟屏幕是一个矩形,它就可以很好地工作,但是一旦它不是(例如 L 形的 3 个屏幕),SystemInformation.VirtualScreen 返回包含所有的最小矩形可见像素(因此 L 右上角的窗口虽然在虚拟屏幕中但不可见)


我试图实现这一点的原因是我希望我的程序在它们所在的最后一个位置打开它的子​​窗口,但是如果用户更改设置,我不希望这些窗口不在视野中(例如从他的笔记本电脑上拔下额外的屏幕)

4

5 回答 5

12

这是我最终的做法:

bool isPointVisibleOnAScreen(Point p)
{
    foreach (Screen s in Screen.AllScreens)
    {
        if (p.X < s.Bounds.Right && p.X > s.Bounds.Left && p.Y > s.Bounds.Top && p.Y < s.Bounds.Bottom)
            return true;
    }
    return false;
}

bool isFormFullyVisible(Form f)
{
    return isPointVisibleOnAScreen(new Point(f.Left, f.Top)) && isPointVisibleOnAScreen(new Point(f.Right, f.Top)) && isPointVisibleOnAScreen(new Point(f.Left, f.Bottom)) && isPointVisibleOnAScreen(new Point(f.Right, f.Bottom));
 }

如果用户的显示设置中有“漏洞”(参见下面的示例),可能会有一些误报,但我认为我的任何用户都不会遇到这种情况:)

   [1]
[2][X][3]
于 2011-07-18T09:11:15.443 回答
6

这是我的做法:

这会将显示边界内的控件(表单)移动到尽可能靠近原始位置的位置。

    private void EnsureVisible(Control ctrl)
    {
        Rectangle ctrlRect = ctrl.DisplayRectangle; //The dimensions of the ctrl
        ctrlRect.Y = ctrl.Top; //Add in the real Top and Left Vals
        ctrlRect.X = ctrl.Left;
        Rectangle screenRect = Screen.GetWorkingArea(ctrl); //The Working Area fo the screen showing most of the Ctrl

        //Now tweak the ctrl's Top and Left until it's fully visible. 
        ctrl.Left += Math.Min(0, screenRect.Left + screenRect.Width - ctrl.Left - ctrl.Width);
        ctrl.Left -= Math.Min(0, ctrl.Left - screenRect.Left);
        ctrl.Top += Math.Min(0, screenRect.Top + screenRect.Height - ctrl.Top - ctrl.Height);
        ctrl.Top -= Math.Min(0, ctrl.Top - screenRect.Top);

    }

当然,要回答您最初的问题,而不是移动控件,您只需检查 4 个 Math.Min 中的任何一个是否返回 0 以外的值。

于 2011-07-06T04:54:18.540 回答
4

我试图做同样的事情来检测窗口是否在屏幕外打开,然后相应地将其重新定位到之前找到它的最近位置。我浏览了整个互联网,但人们提供的所有解决方案都没有奏效。

所以我自己做我自己的课程,正是这样做的,它工作 100%。

这是我的代码

public static class ScreenOperations
{
    public static bool IsWindowOnAnyScreen(Window Window, short WindowSizeX, short WindowSizeY, bool AutoAdjustWindow)
    {
        var Screen = System.Windows.Forms.Screen.FromHandle(new WindowInteropHelper(Window).Handle);

        bool LeftSideTest = false, TopSideTest = false, BottomSideTest = false, RightSideTest = false;

        if (Window.Left >= Screen.WorkingArea.Left)
            LeftSideTest = true;

        if (Window.Top >= Screen.WorkingArea.Top)
            TopSideTest = true;

        if ((Window.Top + WindowSizeY) <= Screen.WorkingArea.Bottom)
            BottomSideTest = true;

        if ((Window.Left + WindowSizeX) <= Screen.WorkingArea.Right)
            RightSideTest = true;

        if (LeftSideTest && TopSideTest && BottomSideTest && RightSideTest)
            return true;
        else
        {
            if (AutoAdjustWindow)
            {
                if (!LeftSideTest)
                    Window.Left = Window.Left - (Window.Left - Screen.WorkingArea.Left);

                if (!TopSideTest)
                    Window.Top = Window.Top - (Window.Top - Screen.WorkingArea.Top);

                if (!BottomSideTest)
                    Window.Top = Window.Top - ((Window.Top + WindowSizeY) - Screen.WorkingArea.Bottom);

                if (!RightSideTest)
                    Window.Left = Window.Left - ((Window.Left + WindowSizeX) - Screen.WorkingArea.Right);
            }
        }

        return false;
    }
}

用法:ScreenOperations.IsWindowOnAnyScreen(WPFWindow, WPFWindowSizeX, WPFWindowSizeY, true); 这将检查窗口是否完全不在屏幕上,即任务栏下方 1 像素或用户当前显示器下方 1 像素。

如果首先打开,它会检测哪个监视器窗口,因此它应该与多监视器一起使用。

如果窗口在屏幕上,则此方法返回 true,否则返回 false。

最后一个参数用于自动将窗口调整到屏幕上最近的部分。如果您为该参数设置 false ,它将不会为您调整窗口。

因此,这是针对此问题的完整 WPF 解决方案,如果您知道如何操作,WinForm 转换应该很容易,将窗口更改为表单并且FromHandle(Form.Handle)应该可以工作。

于 2015-02-19T12:22:24.173 回答
4

这是我的解决方案。它解决了“洞”问题。

    /// <summary>
    /// True if a window is completely visible 
    /// </summary>
    static bool WindowAllVisible(Rectangle windowRectangle)
    {
        int areaOfWindow = windowRectangle.Width * windowRectangle.Height;
        int areaVisible = 0;
        foreach (Screen screen in Screen.AllScreens)
        {
            Rectangle windowPortionOnScreen = screen.WorkingArea;
            windowPortionOnScreen.Intersect(windowRectangle);
            areaVisible += windowPortionOnScreen.Width * windowPortionOnScreen.Height;
            if (areaVisible >= areaOfWindow)
            {
                return true;
            }
        }
        return false;
    }
于 2015-04-23T14:50:26.800 回答
2

检查是否Screen.AllScreens.Any(s => s.WorkingArea.Contains(rect))

于 2011-07-06T02:59:40.127 回答