Dpi scaling что это

Высокие значения DPI в ОС Windows

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

От переводчика

Методы масштабирования

Чтобы исправить ситуацию, Microsoft решила, что неплохо встроить какой-нибудь метод масштабирование в Windows. Один из двух методов описанных ниже (Windows XP или Vista), применяется когда пользователь устанавливает DPI со значением выше чем стандартные 96 точек на дюйм. Оба метода пытаются увеличить размер элементов изображения.

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

Первый из этих методов, как можно догадаться, появился в Windows XP. Этот метод, на самом деле, не является методом масштабирования приложений с графическим интерфейсом как таковой. Масштабируются, при более высоких настройках DPI, только системные шрифты и некоторые элементы пользовательского интерфейса системы (я бы назвал его «метод НЕ масштабирования» в стиле Windows XP).

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

Масштабирование в стиле Windows Vista или DPI виртуализация

Windows Vista представила второй вариант со странным названием, «масштабирование дисплея», без каких-либо уточнений, видимо, чтобы окончательно запутать пользователей. Мы будем использовать более описательное имя – метод DPI виртуализации. Когда этот метод включен, Windows по-прежнему выполняет масштабирование в стиле Windows XP. Также как и прежде размеры всех системных шрифтов и некоторых элементов интерфейса системы увеличиваются.

Разница в том, что приложения, которые могут правильно использовать высокие значения DPI, должны сообщить об этом Windows. Такие приложения должны установить новый DPI-Aware флаг, либо путем вызова функции Win32 API «SetProcessDPIAware», или, предпочтительно, путем встраивания манифеста с флагом dpiAware. А вот если у приложения отсутствует DPI-Aware флаг, Windows ведет себя по другому, сначала она формирует внутреннее отображение в масштабе 96 точек на дюйм (эмулируя для приложения DPI равный 96), а затем, масштабирует полученное изображение в соответствие с текущими настройками DPI перед выводом на экран.

Это было бы фантастическим метод масштабирования если бы все наши мониторы имели плотность пикселей последних аппаратов iPhones (326 точек на дюйм). К сожалению это не так. Окна приложений масштабированные таким образом выглядят чересчур размыто, при популярном разрешении 120 точек на дюйм (@homm это не разрешение, кстати). Поэтому, Microsoft по умолчанию отключает DPI виртуализацию, если вы выберете плотность пикселей меньше или равную 120 DPI.

Как изменить установки DPI

В Windows 7/8, откройте «Панель управления», a затем выберите «Оформление и персонализация», затем «Экран», и, наконец, выберите «Установить размер шрифта (DPI)» (Windows 7) или «Пользовательские параметры размера» (Windows 8). Вы увидите следующее диалоговое окно (Windows 7, в Windows 8 почти идентично):
Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это
Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это
В раскрывающимся списке можно выбрать нужную настройку DPI в процентном соотношении, где 100% соответствует 96 DPI, 125% — как на скриншоте, соответствует 120 точкам на дюйм (можно более точно записать значение вручную). До Windows 8 фактическое значение DPI («пикселей на дюйм») отображалось рядом с размером системного шрифта. Windows 8, по непонятным причинам, не показывает значение DPI, так что вы должны рассчитать его самостоятельно.

Также вы можете приложить линейку (у которой есть шкала в дюймах) к экрану, и пытаться совместить маркировку на ней с маркировкой на экране, изменяя значение в раскрывающимся списке. Флажок, обведенный красным внизу, определяет, следует ли использовать только масштабирование в стиле Windows XP, или также новый способ DPI виртуализации. Если флажок не отмечен, как на скриншоте, то DPI виртуализация включена.

Декламация. Это диалоговое окно пример интерфейса не дружественного к пользователю. На первый взгляд кажется, что это флажок для отключения масштабирования в стиле Windows XP. Но этот метод масштабирования (который только увеличивает системные шрифты и другие элементы пользовательского интерфейса системы — масштабирование Windows XP) всегда включается при выборе высокого значения DPI. На самом деле этот флажок управляет, будет ли этот метод единственным (Использовать только масштабы в стиле Windows XP), или также будет применен метод «DPI виртуализации» для приложений, которые не имеют DPI-Aware флага. Так что этот флажок не контролирует метод масштабирования указанный в его название, а контролирует другой метод масштабирования, нигде не упомянутый — и позволяет использовать новый метод, когда флажок снят!

Ошибка в Windows 8. В дополнение к этому, в Windows 8 это диалоговое окно с ошибкой. Как правило, все работает как и в Windows 7, но состояние флажка не сохраняется на значениях DPI 150% и выше. Когда вы устанавливаете этот флажок, «DPI виртуализация» правильно отключается. Тем не менее, сам флажок остается не отмеченным, когда вы в следующий раз открываете этот диалог.

Изменения в Windows 8.1, или почему все размыто?

В Windows 8.1 флажок для масштабирования в стиле Windows XP исчез, и теперь «DPI виртуализация» никогда, не используется при значениях DPI до 120 включительно, но всегда используется при более высоких значениях для тех программ, у которых отсутствует DPI-Aware флаг. Если некоторые приложения кажутся вам нечеткими, необходимо вручную отключить для них DPI виртуализацию.

Windows 8.1 позволяет использовать несколько мониторов с разным значением DPI. Однако эта функция, также заставляет использовать «DPI виртуализацию» для традиционных приложений, которые перемещаются между мониторами с разными значениями DPI. Чтобы этого избежать, можно отключить в настройках «DPI масштабирование», используя новую опцию «Я хочу выбрать один масштаб для всех дисплеев».

Также Windows 8.1 добавляет специальный переключатель для настройки 200% и новый API, чтобы разработчики могли выборочно отключать «DPI виртуализацию».

Помогите, мои системные шрифты не правильного размера!

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

Если вы на самом деле создали пользовательскую тему рабочего стола и хотите сохранить её, вам придется самостоятельно адаптировать шрифты к новым настройкам DPI. Однако, Windows имеет раздражающую привычку «услужливо» создавать пользовательские темы без вашего ведома, по какой-либо причине. Так что, если вы никогда не создавали пользовательскую тему рабочего стола просто удалите её и вернитесь к стандартной теме.

В Windows 7/8, откройте Панель управления, выберите «Оформление и персонализация», а затем «Персонализация». Если вы видите выбранную запись в строке «Мои темы», это означает, что ОС Windows использует тему пользователя, системные шрифты которой Windows не будет масштабировать. Выберите стандартную тему, например, первую запись в разделе «Темы Aero» (Windows 7) или «Windows» «Темы по умолчанию» (Windows 8) и удалите нежелательные записи в разделе «Мои темы». Теперь, все системные шрифты должны отображаться правильно.

Типы приложений, как они масштабируются (или не масштабируются)

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

DPI-Aware флаг не установленDPI-Aware флаг установлен
Не DPI-AwareНужно использовать DPI виртуализациюНужны исправления от разработчиков
DPI-AwareНужно использовать масштабирование в стиле Windows XPВсегда масштабируется правильно

Приложения вообще не заботящиеся о DPI — это либо очень старые или плохо написанные, но, тем не менее, по-прежнему используемые. Одним известным примером является ITunes от Apple для Windows. Здесь разработчики используют системные шрифты для GUI и, не заботясь о фактических размерах шрифта, они жестко привязывают размеры окон к разрешению 96 DPI, естественно искажая GUI, когда при более высоких значениях DPI увеличиваются размеры шрифтов.

Такие приложения требуют нового метод масштабирования «виртуализации DPI», к сожалению, это часто делает интерфейс размытым. В противном случае вы столкнетесь с проблемами начиная, от обрезания текста до перекрытия элементов контроля, иногда, делая GUI полностью непригодным (к счастью, это, случается редко). За эти годы я собрал несколько образцов скриншотов не корректных приложений.

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это

разрешение 150% (144 DPI)

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это
Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это
Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это

Приложения умеющие подстраивать свой GUI под различные значения DPI, имеющие DPI-Aware флаг — Это новейший тип приложений которые полностью беспроблемны, независимо от настроек DPI. DPI-Aware флаг установлен автоматически для Windows Presentation Foundation (WPF) и GDI+ приложений, так как эти APIs предоставляют встроенные средства масштабирования. Разработчикам использующим старый GDI API и (удивительно) Windows Forms, нужно вручную помечать свои DPI-Aware приложения.

Приложения не приспособленные к изменению DPI, но имеющие DPI-Aware флаг — это еще хуже чем полностью игнорирование значения DPI. В примерах вы найдете GUI приложений, хорошо масштабируемых вплоть до 120 DPI, но не выше, или приложений JavaFX. Тут мы уже ничего сделать не можем, т.к. у нас нет возможности заставить Windows использовать DPI виртуализацию, для таких программ. После того как DPI-Aware флаг установлен, приложение должно масштабировать себя самостоятельно. Мы можем только «пилить» разработчиков исправить их продукт — или использовать что-то другое.

Выбор метода масштабирования для ваших приложений

После того как вы решили что вы хотите использовать высокое значение DPI, ваш выбор метода масштабирования зависит от приложений в которых вы работаете. Имейте в виду, что, отключить «DPI виртуализацию» означает, установить флажок (check box) с некорректным названием «Использовать масштабы в стиле Windows XP» и наоборот.

Напоминаем, что в Windows 8.1 уже нет возможности выбора в этом вопросе. Если вы работаете при разрешении в 120 точек на дюйм (125%), каждая программа будет вынуждена использовать масштабирование в стиле Windows XP, a если вы работаете с более высоким разрешением, каждая программа, которая не является DPI-Aware, будет использовать по умолчанию «DPI виртуализацию».

Отказ от DPI виртуализации для отдельных приложений

После того как вы решили включить DPI виртуализацию или вы работаете в Windows 8.1, с разрешением более чем 120 точек на дюйм, вы можете проверить систему на предмет наличия DPI-Aware приложений, которые не имеют соответствующий флаг. И вернуть им возможность использовать масштабирование в стиле Windows XP, для которого они предназначены. Есть два способа сделать это, первый работает только для 32-разрядных приложений, второй универсален и подходит также для 64-битных приложений.

32-разрядные приложения — Это просто: щелкните правой кнопкой мыши на исполняемом файле в Проводнике Windows, выберите диалоговое окно «Свойства», перейдите на вкладку «Совместимость» и установите флажок «Отключить масштабирование изображения при высоком разрешении экрана». Вот и все, в Windows 8.1 это также работает для 64-битных приложений.

64-разрядные приложения — Без всякой видимой причины, возможно чтобы позлить пользователей 64-битных приложений, в Windows 8 и более ранних, упомянутый выше флажок, для 64-разрядных приложений отключен, хотя сам вариант вполне функционален, если внести изменения непосредственно реестр! Так что, запустите редактор реестра и перейдите к этому ключу:

Теперь добавьте строковое значение (REG_SZ), чье имя является полным путем к исполняемому файлу приложения и значением которого является HIGHDPIAWARE. Я рекомендую, чтобы вы сначала изменили несколько 32-битных приложений, как описано выше, чтобы вы могли увидеть некоторые примеры значений в этом ключе реестра.

Мы рассмотрели, как можно использовать настройки DPI на Windows Vista и более поздних версиях. И если вы когда-нибудь задумывались, для чего предназначена опция совместимости — «Отключить масштабирование изображения при высоком разрешении экрана». И почему она ничего не делает на вашей системе, теперь вы знаете: она эффективна, только если у вас включена общесистемная опция «DPI виртуализации» и только для приложений, которые не устанавливают DPI-Aware флаг должным образом, но при этом корректно используют масштабирование в стиле Windows XP.

Дальнейшее чтение

For more information about both scaling methods from a developer perspective, see the MSDN article Writing High-DPI Win32 Applications. This content has moved to Writing DPI-Aware Desktop and Win32 Applications. This lengthy article also contains a sample manifest to declare an application as DPI-aware, as well as sample screenshots for the various scaling methods and tips on display scaling in native code.

Unfortunately, the article currently only covers Windows XP through 7. See Writing DPI-Aware Desktop Applications in Windows 8.1 Preview (Word DOCX) and Chuck Walbourn’s Manifest Madness for additional information on Windows 8 and 8.1.

Outside of Microsoft, Gastón Hillar has published two articles targeting Windows 8.1 at Dr. Dobb’s. Part 1 covers basic concepts, and part 2 shows C/C++ sample code for the Win32 API.

Источник

Адаптация Qt-приложений под мониторы высокой чёткости. Часть 1

Введение

В связи с техническим прогрессом рынок мониторов постоянно обновляется моделями с повышенным разрешением, плотностью пикселей и/или размером экрана. Году в 2010 стандартным монитором можно было считать экземпляр 19’’ c разрешением WXGA++ (1600*900) и фактической плотностью пикселей 97 DPI (dots per inch). Сейчас (2021 год) стандартным монитором, думаю, можно признать экземпляр 24’’ c разрешением Full HD (1920*1080) и плотностью пикселей 92 DPI. Под «стандартным» я понимаю тот монитор, который стоит на рабочем месте у большинства работающего люда: инженеры, бухгалтеры, переводчики и т.д. (при этом, конечно, «стандартность» — это субъективная и приблизительная оценка). Относительно новые и отчасти нишевые модели (для фотографов, видеографов, геймеров) имеют характеристики: 4K UHD (3840*2160) и 28’’ (157 DPI) или UWQHD (3440×1440) и 34″ (109 DPI) или QHD (2560×1440) и 27″ (109 DPI) или UWHD (2560×1080) и 29″ (96 DPI). Таким образом, наблюдается рост в связанных группах признаков: разрешение+размер экрана, или разрешение+плотность пикселей, или даже разрешение+плотность пикселей+размер экрана. На рынке ноутбуков в плане экранов похожая ситуация – растет разрешение+плотность пикселей.

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

Что касается высокой чёткости (большой плотности пикселей), то в ОС Windows давно есть такие настройки, как масштабирование шрифта и изображений (масштаб экрана), которые применяются для увеличения слишком малых элементов GUI на мониторах с высокой чёткостью (High DPI). Также есть поддержка в платформе Qt (с нюансами, об этом далее). Однако способно ли Ваше, конкретное ПО их адекватно учитывать, применять?

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это

Если пока ещё нет, то в этой статье мы собрали рецепты по адаптации Вашего ПО, написанного на платформе Qt, к современным мониторам высокой четкости. Мы искали и открывали эти рецепты в процессе адаптации одного из наших продуктов. Общий размер кодовой базы GUI – около 200 тысяч строк кода (С++) и 100+ виджетов, код писался разными людьми и в разное время (в том числе и в эпоху 16-пиксельных картинок, которые, как нетрудно догадаться, не очень выгодно выглядят на современных мониторах). В нашей кодовой базе мы нашли целую библиотеку примеров, которые выглядят проблемно на мониторах высокой четкости, и мы постарались эту библиотеку систематизировать, обобщить, упростить и создать на ее базе готовые и легкие для понимания рецепты. В этой статье мы поделимся некоторыми из этих рецептов.

Исходный код примеров был протестирован на Qt5 и Qt6 (более точно – 5.15 и 6.2), на операционках Windows 10 и Windows 7. В основном в статье описаны реалии и будни Qt5 (поскольку именно на Qt5 проблема стоит особенно остро), но рецепты можно с успехом применять и на Qt6 – ничего от этого не поломается.

Пример 1. «Студенческий».

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

Итак, виджет в студию!

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows 10 и Windows7, масштаб экрана 100% А вот и исходный код:

Не будем пока обсуждать, насколько хорош или плох данный код, а сосредоточимся только на том, насколько хорошо виджет выглядит на бОльших масштабах экрана, и что с этим делать. На исходном масштабе в 100% выглядит приемлемо, проблем с GUI нет. А вот при большем масштабировании начинаются проблемы.

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows 10 и Windows7, масштаб экрана 150%

По заголовку видно, что системный, родной шрифт Windows вырос. При этом на Windows 10 наш, запрограммированный, шрифт на виджетах не вырос, а на Windows 7 он вырос, но не поместился по размеру в рамки виджетов. Хорошо, это на данный момент и есть наши проблемы, а как с ними бороться?

Рецепт 1. Настройте DPI Awareness Level.

К счастью, Windows представляет нам готовую системную настройку для работы с высокими DPI. Соответствующая обертка в Qt называется Qt DPI Awareness Level (подробнее см. здесь).

Чтобы произвести настройку, надо всего лишь рядом с выполняемым файлом (exe) приложения положить файл qt.conf со следующим содержимым:

[Platforms]
WindowsArguments = dpiawareness=1

Здесь 1 = System-DPI Aware.

В результате такого нехитрого трюка все стандартные элементы управления Qt (такие, как QLabel, QComboBox, QPushButton и пр.) станут рисовать адекватный шрифт (как в Windows7, так и в Windows10), причем для всех виджетов в рамках всего приложения сразу.

Для сравнения на рисунках ниже показан наш виджет в разных вариациях параметра DPI Awareness Level.

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows 7, 150%, Awareness Level = 0,1,2 (слева направо) Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows 10, 150%, Awareness Level = 0,1,2 (слева направо)

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

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

Рецепт 2. Используйте автокомпоновку.

Ранее в коде мы явным образом размещали элементы управления внутри виджета посредством вызова setGeometry. Аналогичное действие имел бы вызов функций move, resize, setFixedSize. Можно сказать, что это одного поля ягоды. Так вот, следует отказаться от этой порочной практики. Менеджеры компоновки (классы, производные от QLayout) прекрасно справляются с задачей расчета позиции и размера виджета для любых масштабов экрана. Таким образом, в нашем примере нам просто стоит заменить код на следующий:

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

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows 10 и Windows7, масштаб экрана 150% Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows7, масштаб экрана 100%, 125%, 150%.

Здесь очень важно то, что использование автокомпоновки не просто упрощает задачу создания графических интерфейсов, не просто автоматизирует некоторые действия и расчеты, а кардинальным образом меняет сам стиль работы программиста: разработчик ПОЛНОСТЬЮ избавлен от необходимости устанавливать какие-либо фиксированные размеры и координаты, что полностью исключает артефакты отображения при больших масштабах экрана.

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

Пример 2. Анимация движения.

Вот как будет выглядеть наш класс с анимацией:

Нетрудно понять, что после завершения анимации мы получим те проблемы, которые уже видели: текст не будет вписываться в слишком узкие для него рамки:

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows 10 и Windows7, масштаб экрана 150%

Собственно, это произошло именно потому, что значение QRect, которое мы подаем в функцию setEndValue, то же самое, что мы подаем выше (см. пример 1) в функцию setGeometry.

Таким образом, проблема аналогична той, на которую мы вышли в конце рецепта 1, но решать ее надо без автокомпоновщика.

Рецепт 3. Используйте метрику шрифтов при явном задании размеров.

К счастью, в Qt есть возможность через QFontMetrics рассчитывать размеры (ширину, высоту) любых текстовых строк, а значит, можно из них выводить все размеры элементов и все отступы (промежутки) между ними.

Однако, в нашем примере не только текстовые элементы, а иная графика: стрелочки у QComboBox и QSpinBox. Что ж, это не сильно усложняет задачу. Их размеры тоже можно выводить из размера шрифта или явно узнавать из стиля.

Далее будем модифицировать текст примера 1 («Студенческий»), а не примера 2 с анимацией, поскольку последний более сложный, а идею можно понять и на более простом.

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

мы хотим рисовать GUI в три строки,

первые 2 строки имеют табличное размещение (аналогично QGridLayout),

в третьей строке есть 2 кнопки, и они прижаты к левому и правому краю соответственно,

между всеми элементами интерфейса одинаковые отступы.

Итак, эту часть кода можно переписать следующим образом:

Не правда ли, складывается ощущение, что мы реализовали свою автокомпоновку, «навелосипедили»? Да, но без этого в этом примере нельзя.

Далее нам остается лишь заменить установку явных значений для offset, textHeight, buttonHeigh, column1Width, column2Width, okBtnWidth, defBtnWidth на значения, посчитанные из метрики шрифта. Размеры стрелочек для QComboBox и QSpinBox будем узнавать из стилей (хотя можно было бы тоже пытаться примерно высчитать из размера шрифта). Для точного понимания приведем весь код:

После таких манипуляций на любых масштабах экрана виджет будет адекватно выглядеть:

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows7, масштаб экрана 100%, 125%, 150%.

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

Рецепт 4. Не используйте атрибут Qt::AA_EnableHighDpiScaling

Может показаться, что переписывание примера 1 по рецептам 2 или 3 – долгая и ненужная затея, что можно обойтись меньшей кровью. К сожалению, это не так. В Qt5 существуют быстрые и обходные пути решения проблемы High DPI: атрибут Qt::AA_EnableHighDpiScaling, переменные окружения QT_ENABLE_HIGHDPI_SCALING, QT_AUTO_SCREEN_SCALE_FACTOR и прочие. Все эти простые пути приводят к неслабым артефактам. На рисунке ниже приведен пример применения атрибута Qt::AA_EnableHighDpiScaling к коду из примера 1.

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows7, масштаб экрана 100%, 125%, 150%.

На всех масштабах, кроме исходного 100%, видны проблемы. На 125% увеличился текст, но не увеличились размеры виджетов, а на 150% видно (сравните с рисунками из рецептов 2 и 3), что всё увеличилось не в 1.5 раза, а ровно в 2 раза (что неприемлемо), но текст всё равно помещается не везде.

Таким образом, просто установить атрибут Qt::AA_EnableHighDpiScaling и не делать больше ничего (не применять описанные рецепты) не получится, а раз мы все равно вынуждены применять рецепты 2 и 3, то никакой необходимости в быстрых и обходных решениях, типа Qt::AA_EnableHighDpiScaling, попросту нет. Кроме того, атрибут Qt::AA_EnableHighDpiScaling отвратительно масштабирует текст на масштабах 125% (100% вместо 125%), 150% (200% вместо 150%), 175% (200% вместо 175%) и др. Собственно, именно это имелось в виду в документации Qt5 в краткой, как сестра таланта, фразе «Non-integer scale factors may cause significant scaling/painting artifacts».

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

Хорошо, но с начала статьи мы не слова не сказали про иконки и вообще про любые картинки. Что с ними?

Пример 3. Простые иконки.

Добавим в наш простой пример ситуацию, которая вполне могла бы сложиться в реальной жизни в случае, когда приложение разрабатывалось достаточно давно. А именно: приложение может содержать устаревшие, маленькие иконки 16×16 или даже 12×12. Добавим их в текст нашего примера (для случая автокомпоновки, конечно):

На масштабе 100% они выглядят приемлемо (хотя и немного старовато), а вот при бОльших масштабах иконки выглядят слишком мелкими:

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows7, масштаб экрана 100%, 200%, размер иконок 16×16.

Рецепт 5. Увеличьте все иконки или переходите на векторный формат.

В простых случаях, как в описанном примере, достаточно просто заменить растровые иконки размером 16×16 на аналогичные, бОльшие, например, 32×32 или даже 64×64. Также можно заменить растровые иконки на векторные(SVG). Это навсегда закроет проблему больших экранов.

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows7, масштаб экрана 200%, размер иконок 32×32.

Однако такой простой трюк имеет ограниченную область применения. Это будет работать, когда не требуется явно задавать никакие размеры иконок, в том числе не устанавливать собственные стили. Так, для функции QAbstractButton::setIcon в документации явно сказано:

The icon’s default size is defined by the GUI style, but can be adjusted by setting the iconSize property.

То есть если просто вызываем QAbstractButton::setIcon, то будет работать, а если хотим вызвать еще QAbstractButton::setIconSize, то… надо высчитывать размеры иконок, но не из метрики шрифтов (как в рецепте 3), а другим, более простым способом.

Пример 4. Иконки с размерами.

Немного изменим наш пример и добавим туда кнопки с иконками фиксированного размера:

(Отметим, что совершенно неважно, каким именно способом выставляется размер иконок: через QAbstractButton::setIconSize или через задание css-стилей, как здесь. Результат будет одинаковый.)

Как и в примере 3, на масштабе 100% кнопки выглядят приемлемо, а вот при бОльших масштабах иконки выглядят слишком мелкими:

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что этоWindows7, масштаб экрана 100%, 200%, размер иконок 14×14.

Рецепт 6. Используйте экранный масштаб при явном задании размеров.

Qt позволяет нам явно узнать значение экранного масштаба, для этого есть функция QScreen::logicalDotsPerInchX(), которая возвращает значение плотности пикселей в так называемых «логических» координатах. Значение 96 в этой системе координат означает 100% масштаба экрана, значение 120 соответствует масштабу экрана 125%, значение 144 – 150% и т.д. Таким образом, масштаб экрана для класса QWidget можно узнать, например, так:

И в результате получим то, что хотели:

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это

Стоит отметить, что область применения этого рецепта – довольно широкая. Везде, где нелогично и неудобно применять расчет размеров через метрику шрифтов, следует применять расчет размеров через экранный масштаб. Чтобы стало более ясно, что такое «нелогично и неудобно», давайте всё же еще рассмотрим пару примеров на применение этого рецепта.

Пример 5. Стили css.

Предположим, что в нас проснулся Стив Джобс, и мы грезим скругленными кнопками. Модернизируем пример выше следующим образом:

Опять имеем жестко заданные размеры, в том числе и радиус скругления. Чтобы адаптировать такой код, достаточно переписать его вот так:

И в результате получим то, что хотели:

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это

Пример 6. Появление HTML.

Повесим на кнопку Ok слот onOkClicked, в котором будем вызываться QMessageBox с текстом html внутри:

И снова фиксированный размер, и снова используем экранный масштаб:

Итак, с размерами виджетов в простых случаях разобрались. Закрепим приведенные рецепты итоговым алгоритмом их применения:

Dpi scaling что это. Смотреть фото Dpi scaling что это. Смотреть картинку Dpi scaling что это. Картинка про Dpi scaling что это. Фото Dpi scaling что это

На этом рецепты не кончаются, и в случае заинтересованности со стороны читателей могу опубликовать следующую порцию в следующей статье.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *