将SetWindowPos与多个监视器一起使用

时间:2018-10-26 16:29:39

标签: c# windows user32

使用user32.dll和C#,编写了您在下面看到的方法。使用窗口的处理手柄,它将在提供的{x,y}位置设置窗口位置。

但是,在多监视器环境中,下面的代码仅将窗口位置设置为主监视器。我也想选择哪个显示器。
有人可以解释一下如何使用SetWindowPos或与其他user32.dll函数的组合来实现吗?

[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_SHOWWINDOW = 0x0040;

public static void SetWindowPosition(Process p, int x, int y)
{
    IntPtr handle = p.MainWindowHandle;
    if (handle != IntPtr.Zero)
    {
        SetWindowPos(handle, IntPtr.Zero, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
    }
}

基于Jimi的评论的解决方案。

这是我的显示器配置:

enter image description here

观察到我的主监视器左侧有一个辅助监视器。阅读Jimi提供的Virtual Monitor链接后,我发现要将窗口移至次要监视器,我必须使用负x值,因为它位于主要监视器原点的左上角(左上角或<0,0>)。

因此,如果要将窗口位置设置为辅助监视器的<0,0>坐标,则必须从主监视器的原点减去辅助监视器的x宽度,如下所示:

<0,0>-<1920,0> = <-1920,0>

现在,当我在客户端代码中调用SetWindowPosition时,我将其命名为:

SetWindowPosition(Process p, -1920, 0);

注意:如果显示器的分辨率不同,我不知道该怎么办。那是一个更复杂的话题,而不是我要问的问题。另外,由于上面的简单示例解决了我所有的问题,因此我认为无需深入探讨该主题。

1 个答案:

答案 0 :(得分:3)

系统显示配置和VirtualScreen

在Windows系统中,Primary Screen(编程角度)是显示设备,其左上角位置设置为 Point(0,0)

这意味着位于主屏幕的显示器将具有 X坐标(Y坐标可以是如果显示器为纵向布局,则为负)。
上的显示器将具有 X坐标(如果显示器为“纵向”布局,则Y坐标可以为负)。

显示在主屏幕的
换句话说,显示为 Point.X 起源
的显示 Point.X的原点是前面Screens[].Width的所有元素之和,是从主屏幕的Point.X的原点坐标中减去的。

显示在主屏幕的
换句话说,显示具有正面 Point.X 起源
Point.X的原点是前面所有Screens[].Width(包括主要)的总和,并添加到“主屏幕”的原点Point.X坐标中。

示例:
考虑一个具有3个监视器的系统:

PrimaryScreen             (\\.\DISPLAY1):  Width: (1920 x 1080)
Secondary Display (Right) (\\.\DISPLAY2):  Width: (1360 x 768)
Secondary Display (Left)  (\\.\DISPLAY3):  Width: (1680 x 1050)

PrimaryScreen: 
     Bounds: (0, 0, 1920, 1080)      Left: 0      Right: 1920  Top: 0  Bottom: 1080
Secondary Display (Right): 
     Bounds: (1360, 0, 1360, 768)    Left: 1360   Right: 2720  Top: 0  Bottom: 768
Secondary Display (Left): 
     Bounds: (-1680, 0, 1680, 1050)  Left: -1680  Right: 0     Top: 0  Bottom: 1050


Multi Display Disposition 1


如果我们使用系统小程序的主屏幕引用进行更改,将其设置为\\.\DISPLAY3,则坐标将相应地进行修改:

Multi Display Disposition 1


虚拟屏幕

虚拟屏幕是虚拟显示器,其尺寸由以下形式表示:
来源:最左侧的Screen
的原点坐标 宽度:所有Screens宽度的总和。
高度:最高Screen

的高度

这些度量由SystemInformation.VirtualScreen报告
主屏幕SizeSystemInformation.PrimaryMonitorSize报告
还可以使用Screen.AllScreens并检查每个\\.\DISPLAY[N]属性来检索所有屏幕当前的度量和位置。

以前面的示例为参考,在第一个配置中,VirtualScreen的范围是:

Bounds: (-1680, 0, 3280, 1080)  Left: -1680  Right: 3280   Top: 0  Bottom: 1080

在第二种配置中,VirtualScreen的范围是:

Bounds: (0, 0, 4960, 1080)  Left: 0  Right: 4960   Top: 0  Bottom: 1080


显示区域内的窗口位置

Screen class提供了多种方法,可用于确定当前在哪个屏幕上显示特定窗口:

Screen.FromControl([Control reference])
返回包含指定的Screen引用的最大部分的Control对象。

Screen.FromHandle([Window Handle])
返回Screen对象,该对象包含Handle

引用的Window \ Control的最大部分

Screen.FromPoint([Point])
返回包含特定Screen

Point对象

Screen.FromRectangle([Rectangle])
返回包含指定Screen

中最大部分的Rectangle对象

Screen.GetBounds()(超载)
返回引用包含以下内容的屏幕边界的Rectangle结构:
 -特定的Point
 -指定的Rectangle的最大部分
 -Control参考

要确定显示当前表单的\\.\DISPLAY[N],请致电(例如):

Screen.FromHandle(this);

要确定在哪个屏幕上显示辅助表格:
(在示例中使用显示示例)

form2 = new Form2();
form2.Location = new Point(-1400, 100);
form2.Show();
Rectangle screenSize = Screen.GetBounds(form2);
Screen screen = Screen.FromHandle(form2.Handle);

screenSize将是=到\\.\DISPLAY3界。
screen将是表示Screen属性的\\.\DISPLAY3对象。

screen对象还将报告其中显示\\.\DISPLAY[N]的{​​{1}}的{​​{1}}名称。


获取屏幕设备上下文的句柄
一种检索任何可用Display的hDC的通用方法。

当仅需要特定的屏幕参考时,可以使用上述方法之一确定屏幕坐标或屏幕设备。

Screen.DeviceName属性可用作GDI + CreateDC函数的 Screen 参数。它将返回显示的hDC,Graphics.FromHdc可用于创建有效的Graphics对象,该对象将允许在特定的屏幕上进行绘制。

在这里,假设至少有两个显示可用:

form2