如何检查用户屏幕上的窗口是否完全可见?

时间:2011-07-06 02:58:30

标签: c# windows multiple-monitors virtual-screen

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

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


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

5 个答案:

答案 0 :(得分:11)

这是我最终如何做到的:

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]

答案 1 :(得分:4)

我将如何做到这一点:

这会将Display边界内的控件(窗体)移动到尽可能靠近原始位置的位置。

    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以外的其他东西。

答案 2 :(得分:3)

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

答案 3 :(得分:2)

我试图做同样的事情检测窗口是否在屏幕外打开,然后将其重新定位到之前找到的最近的位置。我看着整个互联网,并没有任何人能提供的解决方案。

所以我自己创造了自己的课程,正是这样做,并且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)应该有效。

答案 4 :(得分:1)

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

    /// <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;
    }