Система Отображает расположение и VirtualScreen
В системе Windows, основной экран (перспектива программирования) - это устройство отображения, положение верхнего левого угла которого установлено на Point(0,0)
.
Это означает, что дисплеи, расположенные в слева основного экрана, будут иметь отрицательные X
координаты (координата Y
может быть отрицательной, если дисплей находится в Портретная раскладка).
Дисплеи на вправо будут иметь положительные X
координаты (координата Y
может быть отрицательной, если дисплей находится в книжном макете).
Отображение на влево основного экрана :
Другими словами, дисплеи, имеющие отрицательное Point.X
происхождение
Начало координат Point.X
представляет собой сумму всех предыдущих Screens[].Width
, вычтенных из координат начала координат Point.X
Первичного экрана.
Отображается на Справа Первичного экрана :
Другими словами, дисплеи, имеющие положительное Point.X
происхождение
Начало координат Point.X
- это сумма всех предшествующих Screens[].Width
, Первичных включенных , добавленных к исходной Point.X
координате основного экрана.
Важное примечание :
Если приложение не DPIAware, все эти меры могут быть скомпрометированы виртуализацией и автоматическим масштабированием DPI, выполненным Системой. Все меры будут в форме по умолчанию 96 точек на дюйм: приложение будет получать масштабированные значения. Сюда также входят значения, полученные из функций Api не-DpiAware Win32. Смотри:
Разработка приложений для настольных компьютеров с высоким разрешением под Windows
Включите поддержку всех целевых систем в файле app.manifest
, раскомментировав необходимые разделы.
Добавить / раскомментировать разделы DpiAware и DpiAwareness в файле app.manifest
.
Режим PerMonitorV2 Dpi Awareness можно установить в файле app.config
(доступно в Windows 10 Creators Edition).
Пример:
Рассмотрим систему с 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](https://i.stack.imgur.com/yy3dC.png)
Если мы изменим, используя апплет System, ссылку на основной экран, установив ее на \\.\DISPLAY3
, координаты будут изменены соответственно:
![Multi Display Disposition 1](https://i.stack.imgur.com/w7Ctm.png)
Виртуальный экран
Виртуальный экран - это виртуальный дисплей, размеры которого представлены:
Источник : начальная координата крайнего левого Screen
Ширина : сумма всех Screens
Ширина.
Высота : высота самая высокая Screen
Об этих показателях сообщает SystemInformation.VirtualScreen
Основной экран Size
сообщается SystemInformation.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 предлагает несколько методов, которые можно использовать для определения того, на каком экране в данный момент отображается конкретное окно:
Screen.FromControl([Control reference])
Возвращает объект Screen
, который содержит наибольшую часть указанной ссылки Control
.
Screen.FromHandle([Window Handle])
Возвращает объект Screen
, который содержит самый большой раздел Window \ Control, на который ссылается Handle
Screen.FromPoint([Point])
Возвращает объект Screen
, который содержит определенный Point
Screen.FromRectangle([Rectangle])
Возвращает объект Screen
, который содержит наибольшую часть указанного Rectangle
Screen.GetBounds()
(перегружен)
Возвращает структуру Rectangle
, которая ссылается на границы экрана, содержащие:
- конкретный Point
- самый большой участок из указанных Rectangle
- A 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]
имя Screen
, в котором отображается form2
.
Получить hMonitor
Дескриптор объекта Screen :
Справочный источник .NET показывает, что hMonitor
возвращается, вызывая [Screen].GetHashCode();
IntPtr monitorHwnd = new IntPtr([Screen].GetHashCode());
Или с использованием тех же собственных функций Win32:
MonitorFromWindow , MonitorFromPoint и MonitorFromRect
[Flags]
internal enum MONITOR_DEFAULTTO
{
NULL = 0x00000000,
PRIMARY = 0x00000001,
NEAREST = 0x00000002,
}
[DllImport("User32.dll", SetLastError = true)]
internal static extern IntPtr MonitorFromWindow(IntPtr hwnd, MONITOR_DEFAULTTO dwFlags);
[DllImport("User32.dll", SetLastError = true)]
internal static extern IntPtr MonitorFromPoint([In] POINT pt, MONITOR_DEFAULTTO dwFlags);
[DllImport("User32.dll", SetLastError = true)]
internal static extern IntPtr MonitorFromRect([In] ref RECT lprc, MONITOR_DEFAULTTO dwFlags);
Получение дескриптора контекста устройства экрана :
Универсальный метод для получения hDC любого доступного дисплея.
Координаты экрана или экранное устройство можно определить с помощью одного из методов, описанных ранее, когда требуется только конкретная ссылка на экран.
Свойство Screen.DeviceName можно использовать в качестве параметра lpszDriver
функции GDI + CreateDC . Он вернет hDC дисплея, который Graphics.FromHdc может использовать для создания допустимого объекта Graphics, который позволит рисовать на определенном экране.
Здесь, при условии, что доступно как минимум два дисплея:
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
[DllImport("gdi32.dll", SetLastError = true, EntryPoint = "DeleteDC")]
internal static extern bool DeleteDC([In] IntPtr hdc);
public static IntPtr CreateDCFromDeviceName(string deviceName)
{
return CreateDC(deviceName, null, null, IntPtr.Zero);
}
Screen[] screens = Screen.AllScreens;
IntPtr screenDC1 = CreateDCFromDeviceName(screens[0].DeviceName);
IntPtr screenDC2 = CreateDCFromDeviceName(screens[1].DeviceName);
using (Graphics g1 = Graphics.FromHdc(screenDC1))
using (Graphics g2 = Graphics.FromHdc(screenDC2))
using (Pen pen = new Pen(Color.Red, 10))
{
g1.DrawRectangle(pen, new Rectangle(new Point(100, 100), new Size(200, 200)));
g2.DrawRectangle(pen, new Rectangle(new Point(100, 100), new Size(200, 200)));
}
DeleteDC(screenDC1);
DeleteDC(screenDC2);