Модель автоматизации пользовательского интерфейса и масштабирование экрана

Примечание.

Эта документация предназначена для разработчиков .NET Framework, желающих использовать управляемые классы автоматизации пользовательского интерфейса, определенные в пространстве имен System.Windows.Automation. Последние сведения об автоматизации пользовательского интерфейса см. в статье API автоматизации Windows. Автоматизация пользовательского интерфейса.

Начиная с Windows Vista, Windows позволяет пользователям изменять точки на дюйм (dpi), чтобы большинство элементов пользовательского интерфейса на экране отображались больше. Хотя эта функция уже давно доступна в Windows, в предыдущих версиях масштабирование должно быть реализовано приложениями. Начиная с Windows Vista диспетчер окон рабочего стола выполняет масштабирование по умолчанию для всех приложений, которые не обрабатывают собственное масштабирование. Клиентские приложения модели автоматизации пользовательского интерфейса должны учитывать эту функцию.

Масштабирование в Windows Vista

Параметр dpi по умолчанию равен 96, что означает, что 96 пикселей занимают ширину или высоту одного нотального дюйма. Точный размер "дюйма" зависит от размера и физического разрешения монитора. Например, на мониторе шириной в 12 дюймов при горизонтальном разрешении в 1280 пикселей горизонтальная линия в 96 пикселей имеет протяженность около 9/10 дюйма.

Изменение параметра dpi не совпадает с изменением разрешения экрана. При масштабировании dpi количество физических пикселей на экране остается неизменным. Однако масштабирование применяется к размеру и расположению элементов пользовательского интерфейса. Это масштабирование может автоматически выполняться диспетчером окон рабочего стола для рабочего стола и для приложений, в которых не указан явный запрет на масштабирование.

По сути, когда пользователь устанавливает коэффициент масштабирования на 120 dpi, вертикальный или горизонтальный дюйм на экране становится больше на 25 процентов. Все измерения масштабируются согласованно. Смещение окна приложения от верхнего и левого краев экрана увеличивается на 25 процентов. Если масштабирование приложений включено, и приложение не учитывает dpi, размер окна увеличивается в той же пропорции, а также смещения и размеры всех элементов пользовательского интерфейса, содержащихся в нем.

Примечание.

По умолчанию DWM не выполняет масштабирование для приложений, не поддерживающих dpi, когда пользователь устанавливает значение dpi 120, но выполняет его, если для dpi задано настраиваемое значение 144 или более поздней. Тем не менее пользователь может переопределить поведение по умолчанию.

Масштабирование экрана создает новые проблемы для приложений, которые каким-либо образом связаны с экранными координатами. Теперь экран содержит две системы координат: физическую и логическую. Физические координаты точки являются фактическим смещением в пикселях от верхнего левого угла начала координат. Логические координаты — это смещения, какими они были бы, если бы сами пиксели масштабировались.

Предположим, вы разрабатываете диалоговое окно с кнопкой, имеющей координаты (100, 48). Если это диалоговое окно отображается по умолчанию 96 dpi, кнопка находится в физических координатах (100, 48). В 120 dpi он расположен в физических координатах (125, 60). Но логические координаты одинаковы при любом параметре dpi: (100, 48).

Логические координаты важны, так как они делают поведение операционной системы и приложений согласованными независимо от параметра dpi. Например, Cursor.Position обычно возвращает логические координаты. При перемещении курсора над элементом в диалоговом окне возвращаются те же координаты независимо от параметра dpi. Если вы рисуете элемент управления (100, 100), он рисуется к этим логическим координатам и будет занимать ту же относительную позицию в любом параметре dpi.

Масштабирование в клиентах автоматизации пользовательского интерфейса

API модель автоматизации пользовательского интерфейса не использует логические координаты. Следующие методы и свойства либо возвращают физические координаты, либо принимают их в качестве параметров.

По умолчанию клиентское приложение модель автоматизации пользовательского интерфейса, работающее в среде, отличной от 96-dpi, не сможет получить правильные результаты из этих методов и свойств. Например, поскольку положение курсора определяется в логических координатах, клиент не может просто передать эти координаты в метод FromPoint , чтобы получить элемент, находящийся под курсором. Кроме того, такое приложение не сможет правильно разместить окна за пределами клиентской области.

Решение состоит из двух частей.

  1. Во-первых, сделайте клиентское приложение с поддержкой dpi. Для этого вызовите функцию SetProcessDPIAware Win32 при запуске. В управляемом коде следующее объявление сделает эту функцию доступной.

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    internal static extern bool SetProcessDPIAware();
    
    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Friend Shared Function SetProcessDPIAware() As Boolean
    End Function
    

    Эта функция делает весь процесс с поддержкой dpi, что означает, что все окна, принадлежащие процессу, не масштабируются. Например, в примере средства выделения четыре окна, составляющие прямоугольник выделения, находятся в физических координатах, полученных от модель автоматизации пользовательского интерфейса, а не логических координат. Если образец не учитывается на уровне dpi, выделение будет вырисовано по логическим координатам на рабочем столе, что приведет к неправильному размещению в среде, отличной от 96-dpi.

  2. Чтобы получить координаты курсора, вызовите функцию GetPhysicalCursorPosWin32. В следующем примере показано, как объявлять и использовать эту функцию.

    public struct CursorPoint
    {
        public int X;
        public int Y;
    }
    
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    internal static extern bool GetPhysicalCursorPos(ref CursorPoint lpPoint);
    
    private bool ShowUsage()
    {
        CursorPoint cursorPos = new CursorPoint();
        try
        {
            return GetPhysicalCursorPos(ref cursorPos);
        }
        catch (EntryPointNotFoundException) // Not Windows Vista
        {
            return false;
        }
    }
    
    Structure CursorPoint
        Public X As Integer
        Public Y As Integer
    End Structure
    
    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Friend Shared Function GetPhysicalCursorPos(ByRef lpPoint As CursorPoint) As Boolean
    End Function
    
    Private Function ShowUsage() As Boolean
    
        Dim cursorPos As New CursorPoint()
        Try
            Return GetPhysicalCursorPos(cursorPos)
        Catch e As EntryPointNotFoundException ' Not Windows Vista
            Return False
        End Try
    
    End Function
    

Внимание

Не используйте Cursor.Position. Поведение этого свойства вне клиентских окон в масштабируемой среде не определено.

Если приложение выполняет прямой межпроцессный обмен данными с приложениями, не поддерживаемыми dpi, может быть преобразовано между логическими и физическими координатами с помощью функций PhysicalToLogicalPoint Win32 и LogicalToPhysicalPoint.

См. также