Устранение неполадок приложений для виртуализации DPI и приложений, поддерживающих DPI, в Windows Vista и Windows 7
У меня проблема, когда приложение (написанное в Delphi) ведет себя правильно по умолчанию по умолчанию 96 DPI во всех системах, но ведет себя непоследовательно при настройке "150% размер текста" (внутренне 144 dpi) в разных системах. Похоже, что в некоторых системах некоторые части текста/шрифта моего приложения растягиваются, а в других системах - нет. Я бы подумал, что мое приложение на определенной версии Windows (Win7) в определенном DPI должно вести себя одинаково.
Либо мое приложение сообщит Windows, что ему не нужна функция виртуализации DPI, либо она не будет. Я так понимаю. Я не понимаю, как изменения DPI могут вызывать различный внешний вид на двух машинах, работающих под управлением Windows 7, как при 144 dpi, так и в тех же шрифтах и формах с одинаковыми фиксированными размерами.
Существуют ли зависящие от конфигурации элементы, связанные с виртуализацией DPI, которые мне нужно проверять в Windows (реестр и т.д.)? В противном случае, как вы устраните неполадку и узнаете, выполняется ли виртуализация DPI в окне вашего клиента?
В Delphi необходимо установить для свойства TForm.Scaled значение false, если вы не хотите масштабирования. Но я не понимаю, что, когда свойство основной формы Scaled истинно, я не всегда могу предсказать результат.
Что мне больше всего неприятно в моем приложении, так это то, что у меня есть элемент управления, который имеет только ошибки в моем большом реальном приложении, но который не ошибочно работает в автономном приложении, где я пытаюсь отлаживать только элемент управления. Чтобы понять поведение управления в автономном приложении, я был вынужден сделать демонстрационное приложение, в котором я принудительно передаю сообщение DPI через файл манифеста. Затем я могу воспроизвести сбой контрольного чертежа, хотя в другой форме.
Вот файл манифеста, который я использую в своем демонстрационном приложении, который раскрывает проблемы, с которыми мои элементы управления имеют дело с настройками с высоким разрешением в окнах. Тем не менее, одна странная вещь, которую я обнаружил, заключается в том, что это возможно для приложения
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<assemblyIdentity version="14.0.3615.26342" processorArchitecture="*"
name="TestProject" type="win32"></assemblyIdentity>
<description>High DPI Controls Test App</description>
</assembly>
здесь пример одного из около 30 мест, где элементы управления в моем приложении перепутаны, когда я отключил виртуализацию DPI в своем приложении. Этот конкретный глюк был разрешен путем отключения свойства Scaled в моей форме. Но в других местах, когда TForm.Scaled = false вызывает проблему, тогда как в некоторых формах она исправляет ее:
![DPI Glitch Example with a non-DPI-virtualized app manifest, but main form is Scaled]()
Обновление. Оказывается, некоторые из моих элементов управления используют GDI +, а поведение шрифтов в контекстах GDI + отличается от поведения шрифтов в обычных контекстах GDI, по крайней мере для некоторых сторонних элементов управления, которые используют GDI+. Это главный источник головных болей. Во-вторых, в VCL есть пятнистое тестовое покрытие и плохо определенные требования для осведомленности о ДОИ. Некоторые элементы управления VCL основаны на общих элементах управления MS, и, хотя справедливо утверждать, что базовые общие элементы управления, вероятно, отлично работают в ситуациях с высоким уровнем DPI, можно гарантировать, что не все обертки управления VCL могут работать правильно. Итак, просмотрите приложение для повышения уровня DPI во всех его элементах управления, а также правильное поведение во всех доступных окнах 7 тем:
- aero glass on, при 96dpi (внешний вид Win7 на большинстве современных аппаратных средств)
- основная тема (выключено aero glass), но включены темы xp.
- классический win2000 посмотреть, где стекло выключено, а также темы уровня xp,
- высококонтрастный белый
- высококонтрастный черный
- Различные настройки, отличные от 96-DPI
.. и список продолжается. И у вас довольно тяжелое бремя, как разработчик приложения. Являетесь ли вы пользователем delphi и используете VCL, или вы являетесь разработчиком MFC/ATL С++, мне кажется, что поддержка всех различных причудливых оконных режимов - это слишком тяжелое бремя. Поэтому большинство людей не беспокоится. Я прав?
Ответы
Ответ 1
Оказывается, что причуды в моем приложении, когда система DPI изменилась с значения 96 dpi по умолчанию, находятся в трех общих лагерях:
-
Некоторые элементы управления приложениями используют GDI, а некоторые элементы управления используют GDI+. Существуют некоторые различия в том, как GDI и GDI + шрифт отображаются в разных DPI, по крайней мере, в элементах управления, которые я использую.
-
Я использую фреймворк VCL в delphi. В этой структуре Delphi VCL некоторые формы имеют TForm.Scaled = true, а некоторые имеют TForm.Scaled = false. Поскольку это требует, чтобы вы думали о каждом элементе управления в масштабированной форме, очень часто случается, что вы, как разработчик пользовательского интерфейса, найдете "уродливым" или неприемлемым в масштабированной форме. При повороте Scaled off вы остаетесь с формами, которые либо растягиваются самой Windows 7, либо с высокими настройками DPI (режим виртуализации DPI), либо кажутся маленькими и, следовательно, игнорируют пользовательский "запрос", если хотите, для версии с разрешением 144 dpi ваш пользовательский интерфейс с разрешением 96 точек на дюйм. Другие люди могут использовать другие фреймворки на других языках или даже могут использовать что-то действительно старомодное, например, редактор диалогового окна для Visual С++, где вы создаете диалоги в "Dialog Units", что является еще одним способом отделить общий диалог макет, от соответствия 1:1 пикселям. Масштабирование, растяжка и компоновка являются общей частью дизайна пользовательского интерфейса, которая должна быть решена таким образом, чтобы соответствовать требованиям платформы. В моем случае VCL отлично справляется с тем, что я могу создать приложение для аэродинамического стекла с разрешением 96 точек на дюйм и отлично работает в других рейтингах DPI, но большинство моих пользовательских элементов управления не работают. Так что это еще одна причина придерживаться элементов управления, которые поставляются с VCL: если вы заботитесь о высокой поддержке DPI, ваша работа усложняется, когда вы пытаетесь сделать работу с поддержкой DPI.
-
Виртуализация DPI, в свою очередь, контролируется установкой манифеста, которую вы должны явно включить в ваше приложение. Поскольку у моего приложения уже был пользовательский манифест (не тот, который включен в приложение Delphi, когда вы нажимаете флажок "Включить-окна-темы" в настройках проекта), я смог снова включить эту виртуализацию DPI и проверить моя заявка в обоих случаях. Я обнаружил, что мое приложение не было готово работать без виртуализации DPI, и поэтому я оставил Windows по умолчанию. Приложения других пользователей могут легко работать с отключением виртуализации DPI, если они используют 100% -ные элементы управления vcl, с формами, которые используют масштабирование формы или какую-либо другую технику, чтобы соответствующим образом определять размер (например, элемент управления VCL ExpressLayout из DevExpress) при различных размер шрифта и шаг DPI.). Мне кажется, что в конечном итоге VCL достаточно функциональен, но для действительно промышленных решений необходимы более продвинутые рамки, чем VCL, для всестороннего решения таких проблем, как "среды с высоким уровнем DPI", и что сторонние элементы управления, как правило, не предназначены для работы, как и текущие работы VCL, в этих случаях. Подобные проблемы с каркасом очень широко представлены в рамках WPF (Microsoft) и на Java (крыло), но не являются частью классической "общей структуры управления Win16/Win32" VCL.
В целом, эти изменения сейчас не такие разные (сложные), как в старые времена, когда Windows XP и другие версии Windows предложили вам выбор "размеров шрифтов", тогда как теперь опыт работы с Windows 7 UI пытается довольно хоронить параметры размера шрифта, и вместо этого предлагает вам изменяющийся пользовательский интерфейс "размер текста", который изменяет системный DPI под поверхностью. Оба этих способа изменения пользовательского интерфейса приводят к тому, что почти у каждого пользователя возникают проблемы с по крайней мере одним крупным коммерческим приложением, которое не выглядит или работает корректно с полученными изменениями. Поскольку ультравысокие индикаторы точки тона становятся более распространенными в ландшафте потребительского ПК, эта проблема, вероятно, будет все хуже и хуже, и потребуется дизайн пользовательского интерфейса вокруг более подходящих фреймворков.
Ответ 2
Вам нужно продемонстрировать, что ваше приложение поддерживает DPI с таким разделом:
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
Если вы это сделаете, вы не получите виртуализацию DPI.
Вы не должны использовать виртуализацию DPI, поэтому я думаю, что нет смысла пытаться понять, как это работает. Он может легко зависеть от драйверов видеокарты. Нам почти невозможно объяснить, почему виртуализация ведет себя так: вы даже не дали скриншотов, деталей оборудования и т.д. Однако вам просто не стоит пытаться диагностировать это. Манифест как dpiaware, и это не проблема.
Для справки я предлагаю вам:
Ответ 3
В окне "Пользовательские настройки DPI" есть "Использовать масштабирование DPI в стиле Windows XP". Это может объяснить различное поведение.
Ответ 4
На самом деле это другой вопрос.
Ваши формы не должны увеличиваться с помощью пользователя DPI, они должны увеличиваться с размером шрифта.
Размер шрифта по умолчанию Delphi 8pt Tahoma.
средний 8pt Характер Tahoma: 6.08px * 13px
.
Начиная с Windows Vista, шрифт по умолчанию 9pt Segoe UI.
средний 9pt Segoe UI-символ: 6.81px * 15px
.
![enter image description here]()
Приложения Windows должны соблюдать предпочтение шрифта пользователя (т.е. IconTitleFont
).
Мой предпочтительный шрифт Windows 12pt Segoe UI, средний размер которого: 8.98px * 21px
:
![enter image description here]()
Это означает, что если вы создали свою форму в Tahoma 8pt (максимум 13 пикселей), вам необходимо масштабировать форму и все дочерние элементы управления на 162%:
scaleFactor = (userFontSize / designedFontSize)
= 21px / 13px
= 1.615
Если вы будете осторожны, вы заметите, что изменение DPI - это особый случай изменения размера шрифта. Ваш 8pt шрифт по-прежнему 8pt, но 8pt переводится в большее количество пикселей. Если вы запустите 131dpi (136% настройки масштабирования в Windows 7), выполните следующие действия:
9pt Segoe UI, 96dpi = 6.81px x 15px
9pt Segoe UI, 131dpi = 8.98px x 21px
![enter image description here]()
Примечание: Не совпадение, что я выбрал 131dpi
и 12pt
в качестве своих примеров. На работе я запускаю 96dpi, но 12pt. Дома я запускаю 9pt, но 131dpi. Оба имеют ту же высоту шрифта пикселя, 21px.
В конце вам нужно называть ScaleControl
разницей размеров:
procedure StandardizeFormFont(Form: TForm);
var
iconTitleFontName: string;
iconTitleFontSizePixels: Integer;
currentFontSizePixels: Integer;
begin
GetIconTitleFont(iconTitleFontName, iconTitleFontSizePixels);
//Change font face first
//Some fonts are inheriently taller than others
//(even at the same point size)
Form.Font.Name := iconTitleFontName;
//Get the form current font height (in pixels)
currentFontSizePixels := Form.Font.Height; //negative number, but so is iconTitleFontSizePixels
Form.ScaleBy(iconTitleFontSizePixels, currentFontSizePixels);
end;
В действительности этот код очень упрощен. Многие дочерние элементы управления необходимо обновить вручную:
- столбцы списка должны расширяться
- Элементы управления
ParentFont = false
должны иметь свой шрифт.
- Элементы управления TImage должны растягивать изображение до нового размера.
- панель инструментов должна использовать большие изображения
В действительности мы используем супер-фантазийную версию StandardizeFormFont
, которая рекурсивно проходит через все элементы управления в форме и лучше всего настраивает каждый элемент управления на основе того, что это такое.
Каждый элемент управления Delphi должен переопределить метод ScaleControl
и выполнить необходимые ему настройки:
protected
procedure ChangeScale(M, D: Integer); override;