Высокий DPI Scaling Улучшения для настольных приложений в обновлениях Windows 10

27 Окт 2016 | Автор: | Комментариев нет »

Поскольку технология отображения улучшилась с течением времени, передний край переместился в сторону, имеющий большее количество пикселей, запакованные в каждый физический квадратный дюйм, и от просто делает дисплеи физически больше. Эта тенденция увеличила количество точек на дюйм (DPI) дисплеев на рынке сегодня.

Surface Pro 4, например, имеет примерно 192 DPI (в то время как устаревшие дисплеи имеют 96 точек на дюйм). Несмотря на то, имея большее количество пикселей, запакованные в каждый физический квадратный дюйм дисплея может дать вам очень четкую графику и текст, он также может вызвать проблемы для разработчиков настольных приложений. Многие настольные приложения отображаются размыто, неправильно размера UI (слишком большой или слишком маленький), или непригодными для использования при использовании высоких дисплеев DPI в сочетании с стандартной DPI дисплеев.

Многие структуры рабочего стола пользовательского интерфейса, которые разработчики полагаются на создание приложений для настольных компьютеров Windows, изначально не ручка высокого DPI дисплеев и работы требуется со стороны разработчика для решения изменения размера UI приложения на этих дисплеев. Это может быть очень дорогим и трудоемким процессом для разработчиков. В этом посте я расскажу о некоторых из усовершенствований, введенных в Юбилейном Центр обновления Windows 10, которые делают его менее дорогостоящим для разработчиков приложений рабочего стола для разработки приложений, которые обрабатывают с высоким DPI отображается правильно.

Обратите внимание, что приложения, построенные на Windows, Универсальная платформа (UWP) Ручка дисплея масштабирования очень хорошо, и что содержание обсуждалось в этой должности не относится к UWP. Если вы создаете новое приложение для Windows или находятся в положении, когда мигрирующие возможно, рассмотреть UWP, чтобы избежать проблем, которые обсуждались на этом посту.

Некоторые Справочная информация о DPI Scaling

Стив Райт написал на эту тему подробно, но я думал, что суммировать некоторые сложности масштабирования вокруг дисплея для настольных приложений здесь. Многие настольные приложения (приложения, написанные в сыром Win32, MFC, WPF, WinForms или другие структуры UI) часто может стать расплывчатым, неправильно размера или комбинация обоих, когда масштабный фактор дисплея или DPI, дисплея, что они находятся на отличается, чем это было, когда сеанс Windows, впервые был запущен.

Это может произойти при многих обстоятельствах:

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

В прошлом, Windows не предложила никакой поддержки DPI масштабирования к приложениям на уровне платформы. Когда этот тип "DPI" приложения не знают работают на Windows 10, они почти всегда растрового изображения масштабируются окна, когда масштабирование дисплея> 100%. Позже, Windows ввел режим DPI-информирования под названием "Система DPI Awareness." Система DPI Awareness предоставляет информацию о приложениях коэффициента отображения масштаба, размера экрана, информацию о правильных шрифтов для использования, и т.д., так что разработчики могут имеют свои приложения правильно масштабируется для дисплей с высоким DPI. К сожалению, система DPI Осведомленность не был разработан для сценариев динамического масштабирования, таких как док / расстыковки, перемещение окна приложения к дисплею с различным коэффициентом отображения шкалы и т.д. Другими словами: модель для системы-DPI-осознания, что является одним предполагает, что только один дисплей будет использоваться в течение всего жизненного цикла приложения и что масштабный коэффициент не изменится.

В сценариях динамического масштабирования фактор приложения будут растровый растягивают Windows, когда дисплей масштаба фактор изменился (это относится даже к системно-DPI-осведомленных процессов). Окна 8.1 введена поддержка "Per-монитор-DPI Awareness", чтобы позволить разработчикам создавать приложения, которые могли бы изменить размер на основе каждого DPI. Приложения, которые регистрируют себя как Per-Monitor-DPI Aware информируются при изменении коэффициента масштаба отображения и, как ожидается, реагировать соответствующим образом.

Так что ... все было хорошо, не так ли? Не совсем.

К сожалению, были три большие пробелы с нашей реализации Per-Monitor-DPI Осведомленность в платформе:

Там не было достаточной поддержки платформы для разработчиков настольных приложений на самом деле сделать их приложения делать правильные вещи, когда дисплей масштаба фактор изменился.
Это было очень дорого, чтобы обновить интерфейс приложения, чтобы правильно реагировать на дисплей масштабных изменений коэффициента, если это вообще было возможно сделать на всех.
Там не было никакого способа напрямую отключить окна Bitmap-масштабирование интерфейса приложения. Некоторые приложения зарегистрировать себя как Per-Monitor-DPI Aware не потому, что они на самом деле были в курсе DPI, а потому, что они не хотят, чтобы Windows, растровые растянуть их.

Эти проблемы привели к очень немногих приложений обработки динамического масштабирования дисплея правильно. Многие приложения, которые зарегистрировали себя как Per-монитор-DPI Aware не масштабируются на всех, и может оказать чрезвычайно большой или крайне мало на вторичных дисплеев.

Общие сведения о проводнике

Как я уже говорил в другом блоге, в ходе цикла разработки для первого выпуска Windows 10 мы решили начать улучшать путь Windows, обрабатывается масштабирование динамического отображения путем обновления некоторых компонентов пользовательского интерфейса в коробке, такие как Windows, File Explorer, чтобы правильно масштабировать.

Это был большой опыт для нас, потому что учил нас о проблемах, разработчики сталкиваются при попытке обновить свои приложения, чтобы динамически масштабировать и где Windows, был ограничен в связи с этим. Одним из основных уроков, извлеченных в том, что, даже для простых приложений, модель регистрации приложения либо как система DPI Aware или Per-монитор-DPI Aware был слишком жестким из требования, поскольку это означало, что если разработчик решил пометить их Приложение, как в соответствии с одним из этих режимов DPI-информирования, они должны были бы обновить все окна верхнего уровня в их применении или жить с некоторыми окна верхнего уровня имеет размер неправильно. Любое приложение, которое принимает контент сторонних производителей, таких как плагинов или расширений, не могут даже иметь доступ к исходному коду для этого содержания и, следовательно, не сможет подтвердить, что он обрабатывается масштабирование дисплея правильно. Кроме того, было много компонентов системы (ComDlg32, например), которые не масштабируются на основе каждого DPI.

Когда мы обновили приложение File Explorer (в кодовую, что было вокруг, и была добавлена ​​в течение некоторого времени), мы продолжали находить все больше и больше пользовательский интерфейс, который должен был быть обновлен, чтобы обрабатывать правильно масштабировать, даже после того, как мы достигли точки в процессе развития, когда основной UI масштабируются правильно. В этот момент мы столкнулись с такой же выбор другие разработчики столкнулись: мы должны были коснуться старого кода для реализации динамического масштабирования (который поставляется вместе с рисками совместимости приложений) или жить с этими компонентами пользовательского интерфейса быть размером неправильно. Это помогло нам чувствовать боль, что разработчики сталкиваются при попытке придерживаться жесткой модели, Windows, от них требуется.

Смешанный режим DPI Scaling и контекст DPI-Awareness

Урок выучен. Было ясно, что нам нужно, чтобы распадаться этот жесткий, процесс в масштабах всей, модель для масштабирования дисплея, требуемого для Windows. Наша цель состояла в том, чтобы сделать его проще для разработчиков, чтобы обновить свои настольные приложения для обработки масштабирование динамического отображения так, чтобы больше настольных приложений будет масштабировать корректно на Windows, 10. Идея мы придумали было перенести ограничение на уровне процессов на дисплее масштабирования к верхнего уровня уровня окна. Идея заключалась в том, что вместо того, чтобы требовать каждого отдельного окна верхнего уровня в настольном приложении необходимо обновить для масштабирования с использованием одного режима, мы могли бы вместо того, чтобы позволить разработчикам простоту в, так сказать, к миру с динамическим DPI, позволяя им выбрать режим масштабирования для каждого окна верхнего уровня. Для приложения с главного окна и вторичного пользовательского интерфейса, такие как CAD или иллюстрации применения, например, разработчики могут сосредоточить свое время и энергию обновления основного пользовательского интерфейса для Windows, позволяя ручки масштабирования менее важный интерфейс, возможно, с растровый растяжку. Хотя это не было бы идеальным решением, это позволит разработчикам приложений обновить свой пользовательский интерфейс в своем собственном темпе, вместо того, чтобы требовать их обновлять каждый компонент их UI сразу, или страдать от последствий ранее упомянутых.

Windows, 10-летие Обновление было введено понятие "Mixed-Mode" DPI масштабирования, также известный как суб-процесса DPI масштабирования, с помощью концепции контекста DPI-информирования (DPI_AWARENESS_CONTEXT) и SetThreadDpiAwarenessContext API. Вы можете думать о контексте DPI по повышению осведомленности в режиме, что поток может быть, в которой может повлиять на поведение DPI-вызовов API, которые сделаны с помощью нити (в то время как в одном из этих режимов). Режим работы нити, либо контекст, может быть изменен с помощью звонков на SetThreadDpiAwarenessContext в любое время.

Вот некоторые ключевые моменты, которые необходимо учитывать:

    Поток может иметь свой DPI Осведомленность Контекст изменен в любое время.
    Любые API вызовы, которые сделаны после того, как контекст меняется будет работать в соответствующем контексте DPI (и может быть виртуализированы).
    Когда поток, который работает с данным контекстом, создает новое окно верхнего уровня, новое окно верхнего уровня будет присвоен тот же контекст, что поток, который создал это было, в момент создания.
    Давайте обсудим первый пункт: С SetThreadDpiAwarenessContext контекст нити может переключаться по своему желанию. Темы также могут быть включены в и из разных контекстов несколько раз.

Многие API вызовы Windows, в Windows, будет возвращать различную информацию к приложениям в зависимости от режима осведомленности DPI, что вызывающий процесс запущен. Например, если приложение DPI-не знают (что означает, что он не уточнил, режим DPI-Awareness ) и работает на фактор масштаба отображения больше чем на 100%, и если это приложение запрашивает для Windows, размера дисплея, Windows возвращает размер дисплея, пересчитанных в пространстве координат приложения. Этот процесс называется виртуализации. До наличия смешанного режима DPI, это виртуализация происходило только на уровне процесса. Теперь это можно сделать на уровне потоков.

Смешанный режим DPI масштабирование должно значительно уменьшить барьер для входа для поддержки DPI для настольных приложений.

Создание Блокнот Per-монитор DPI Aware

Теперь, когда я ввел понятие смешанного режима, давайте поговорим о том, как мы применили его к фактическому применению. В то время как мы работали на смешанном режиме, мы решили попробовать его на некоторых приложениях в коробке Windows. Первое приложение, которое мы начали с Блокнот был. Блокнот является по существу приложением одного окна с помощью одного органа управления редактирования. Он также имеет несколько "уровень 2" UI, такие как диалог шрифта, диалог печати и диалог поиска / замены. До юбилейного обновления Windows 10, Блокнот был система-DPI-Aware процесс (хрустящий на основном дисплее, размыто на других или если фактор масштаб отображения изменился). Наша цель состояла в том, чтобы сделать его первый класс Per-монитор-DPI-Aware процесс так, что она будет оказывать решительно в любой масштабный фактор.

Одна из первых вещей, которые мы сделали, чтобы изменить манифест приложения для блокнота, так что она будет работать в режиме за мониторами. После того, как приложение работает в соответствии с мониторами и DPI изменяет процесс посылается сообщение WM_DPICHANGE. Это сообщение содержит предлагаемый прямоугольник, чтобы размер приложения к использованию SetWindowPos. После того, как мы сделали это и переехал Блокнот второй дисплей (дисплей с другой масштабный коэффициент), мы увидели, что область не-клиент окна не масштабирования автоматически. Область не-клиент может быть описана как все окна хрома, которая рисуется операционной системой, такие как кнопка мин / макс / закрытия, границы окна, системное меню, строке заголовка и т.д.

Вот картина Блокнот с его неиспользованием клиентской области правильно DPI масштабирования рядом с другим каждого монитора приложение, которое имеет площадь не-клиент, который не масштабируется. Обратите внимание на то, как область не-клиент второго приложения меньше. Это происходит потому, что дисплей, что его образ был взят в плен на масштабировании используется показатель 200%, в то время как область не-клиент был инициализирован при масштабировании 100% (система) дисплея.

обновления Windows 10

обновления Windows 10

Во время первого выпуска Windows 10 мы разработали функциональность, которая позволила бы область не-клиент для масштабирования динамически, но он не был готов к прайм-тайм и не был выпущен публично, пока мы не выпустили Anniversary Update.

Мы смогли использовать EnableNonClientDpiScaling API, чтобы получить не-клиентскую область Блокноте автоматически масштабируются DPI.

Использование EnableNonClientDpiScaling позволит автоматическое масштабирование DPI в области неклиентской для окна, когда выполняются следующие условия:

  • API вызывается из обработчика WM_NCCREATE для окна
  • Процесс или окно работает в каждого монитора-DPI осведомленности
  • Окно передается API является окном верхнего уровня (только окна верхнего уровня поддерживаются)

Размер шрифта & ChooseFont Dialog

Следующее, что должно было быть сделано в том, чтобы изменить размер шрифта на изменении DPI. Блокнот использует элемент управления редактирования для своего основного пользовательского интерфейса, и он должен иметь указан размер шрифта. После изменения DPI, предыдущий размер шрифта был либо слишком велик или слишком мал для нового масштабного фактора, так что это должно было быть пересчитаны. Мы использовали GetDpiForWindow основывать расчет для нового размера шрифта:

FontStruct.lfHeight = -MulDiv(iPointSize, GetDpiForWindow(hwndNP), 720);

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

image214-300x217

Для решения этой проблемы мы использовали в смешанном режиме, чтобы диалоговое окно выполнения ChooseFont с контекстом системы DPI-информирования. Это означало, что этот диалог будет масштабироваться до системы DPI на основном дисплее и быть растянуты растрового изображения в любое время масштабный фактор дисплея изменен:

DPI_AWARENESS_CONTEXT previousDpiContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
BOOL cfResult = ChooseFont(cf);
SetThreadDpiAwarenessContext(previousDpiContext);

Этот код хранит DPI_AWARENESS_CONTEXT нити, а затем временно изменяет контекст пока диалог ChooseFont создается. Это гарантирует, что диалог ChooseFont будет работать с контекстом системы DPI-информирования. Сразу же после того, как вызов для создания окна, контекст осознания Нить будет восстановлена, потому что мы не хотели нить, чтобы ее понимание изменились навсегда.

Мы знали, что диалог ChooseFont сделал осведомленность поддержки системы DPI поэтому мы выбрали DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, в противном случае мы могли бы использовать DPI_AWARENESS_CONTEXT_UNAWARE по крайней мере, обеспечить, чтобы этот диалог был бы точечный рисунок растягивается на правильный физический размер.

Теперь мы имели диалог ChooseFont масштабирования должным образом, не касаясь любой из кода диалогового окна ChooseFont, но это приведет к нашей следующей задачей ... и это одна из наиболее важных понятий, которые разработчики должны понимать об использовании смешанного режима DPI масштабирования: данные общими для всех контексты DPI-информирования может быть с использованием различных масштабирования / координат пространства и может иметь различные интерпретации в каждом контексте. В случае диалога ChooseFont, то эта функция возвращает размер шрифта на основе от ввода пользователя, но этот размер шрифта возвращенное относительно масштабного фактора, что диалог работает. Когда главное окно Блокнот работает на масштабный коэффициент что отличается, чем фактор системного масштаба, значения из диалога ChooseFont должны быть переведены, чтобы быть значимым для масштабного коэффициента главного окна. Здесь мы масштабируется размер шрифта в пунктах к DPI дисплея, что окно Блокнот был запущен на, опять же с помощью GetDpiForWindow:

FontStruct.lfHeight = -MulDiv(cf.iPointSize, GetDpiForWindow(hwndNP), 720);

Этот код хранит DPI_AWARENESS_CONTEXT нити, а затем временно изменяет контекст пока диалог ChooseFont создается. Это гарантирует, что диалог ChooseFont будет работать с контекстом системы DPI-информирования. Сразу же после того, как вызов для создания окна, контекст осознания Нить будет восстановлена, потому что мы не хотели нить, чтобы ее понимание изменились навсегда.

Мы знали, что диалог ChooseFont сделал осведомленность поддержки системы DPI поэтому мы выбрали DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, в противном случае мы могли бы использовать DPI_AWARENESS_CONTEXT_UNAWARE по крайней мере, обеспечить, чтобы этот диалог был бы точечный рисунок растягивается на правильный физический размер.

Теперь мы имели диалог ChooseFont масштабирования должным образом, не касаясь любой из кода диалогового окна ChooseFont, но это приведет к нашей следующей задачей ... и это одна из наиболее важных понятий, которые разработчики должны понимать об использовании смешанного режима DPI масштабирования: данные общими для всех контексты DPI-информирования может быть с использованием различных масштабирования / координат пространства и может иметь различные интерпретации в каждом контексте. В случае диалога ChooseFont, то эта функция возвращает размер шрифта на основе от ввода пользователя, но этот размер шрифта возвращенное относительно масштабного фактора, что диалог работает. Когда главное окно Блокнот работает на масштабный коэффициент что отличается, чем фактор системного масштаба, значения из диалога ChooseFont должны быть переведены, чтобы быть значимым для масштабного коэффициента главного окна. Здесь мы масштабируется размер шрифта в пунктах к DPI дисплея, что окно Блокнот был запущен на, опять же с помощью GetDpiForWindow:

DPI_AWARENESS_CONTEXT previousDpiContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
BOOL ret = SetWindowPlacement(hwnd, wp);
SetThreadDpiAwarenessContext(previousDpiContext);

После того, как все эти изменения были сделаны, мы Блокнот масштабирования красиво каждый раз, когда DPI изменится и текст документа рендеринга изначально для каждого DPI, который был большой шаг вперед по сравнению имея Windows Bitmap растянуть приложение на изменения DPI.

Полезные утилиты DPI

Во время работы над масштабированием смешанного режима отображения, мы столкнулись с необходимостью иметь DPI-Aware варианты некоторых наиболее часто используемых API:

  • AdjustWindowRectExForDpi
  • GetDpiForSystem
  • GetDpiForWindow
  • GetSystemMetricForDpi
  • SystemParametersInfoForDpi
  • Примечание о GetDpiForSystem: ВЫЗОВ GetDpiForSystem является более эффективным, чем вызов GetDC и GetDeviceCaps, чтобы получить систему DPI.

Кроме того, любой компонент, который может быть запущен в приложении, которое использует подпроцесс осведомленность DPI не следует считать, что система DPI является статическим в течение всего жизненного цикла процесса. Например, если поток, который работает под управлением контексте повышения DPI_AWARENESS_CONTEXT_UNAWARE запросов системы DPI, ответ будет 96. Однако, если тот же поток перешел на DPI_AWARENESS_CONTEXT_SYSTEM и запрашиваются систему DPI снова, ответ может быть различным. Для того, чтобы избежать использования кешированная - и, возможно, несвежий - системный DPI значение, используйте GetDpiForSystem (), чтобы получить систему DPI относительно режима DPI-информирования вызывающего потока.

Что мы не получили

Windows 10 Anniversary Update обеспечивает полезный API для разработчиков, которые хотят обновить настольных приложений для поддержки динамического масштабирования DPI в своих приложениях, в частности EnableNonClientDpiScaling и SetThreadDpiAwarenessContext (также известный как "смешанном режиме"), но есть еще некоторые отсутствующие функции, что мы были не в состоянии поставить. общие элементы управления Windows (COMCTL32.DLL) не поддерживают за монитор DPI масштабирование и не клиентская область DPI-масштабирование поддерживается только для окон верхнего уровня (дочернего окна области без клиента, например, полосы прокрутки дочернего окна не автоматически масштабировать для DPI (даже в юбилейном Update)).

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

Как уже упоминалось в моем другом посте, WPF предлагает за монитор поддержки DPI-информирования, а также.

Пример приложения в смешанном режиме:

Мы собрали образец, который показывает основы того, как использовать смешанный режим осведомленности DPI. Проект связан ниже создает окно верхнего уровня, которое за монитор DPI в курсе и имеет не-клиентскую область автоматически масштабируется. В меню вы можете создать вторичное окно, которое использует DPI_AWARENESS_CONTEXT_SYSTEM_AWARE контекст, так что для Windows будет растровый растягивать содержимое при его визуализации в другом DPI.

Вывод

Наша цель состояла в том, чтобы снизить стоимость для разработчиков, чтобы обновить свои настольные приложения, чтобы быть за монитор DPI в курсе. Мы признаем, что все еще существуют пробелы в функциональности DPI-масштабирования, что для Windows предоставляет разработчикам настольных приложений и важность полного разблокирования разработчиков в этом пространстве. Следите за благость, чтобы прибыть.

Перевод статьи с сайта: https://blogs.windows.com

Здесь вы можете написать комментарий к записи "Высокий DPI Scaling Улучшения для настольных приложений в обновлениях Windows 10".

* Обязательные для заполнения поля
Все отзывы проходят модерацию.
Мы в VK
Наши партнеры
Читать нас
Связаться с нами
Наши контакты

info@windowsfan.ru

О сайте

Информационно-познавательный интернет журнал про Windows