Ответ 1
Если бы я начал новую заявку с намерением поддержка на уровне мониторинга DPI, какой наилучший подход?
Мы не полагаемся на Qt для автоматического масштабирования в режиме мониторинга с DPI-монитором. По крайней мере, приложение на основе Qt 5.7 с набором Qt::AA_EnableHighDpiScaling
этого не делает, а "высокое масштабирование DPI" является более точным чертежом, независимо от плотности пикселей.
И для вызова режима просмотра с поддержкой DPI для каждого монитора вам нужно изменить файл Qt.conf
в том же каталоге, в котором вы создаете исполняемый файл проекта:
[Platforms]
# 1 - for System DPI Aware
# 2 - for Per Monitor DPI Aware
WindowsArguments = dpiawareness=2
# May need to define this section as well
#[Paths]
#Prefix=.
Если я правильно понимаю, Qt:: AA_EnableHighDpiScaling - это напротив того, что я хочу. Я должен фактически отключить HighDpiScaling и рассчитать все размеры вручную во время выполнения?
Нет, это не противоположность, а другое. Есть пара ошибок Qt, которые были закрыты как no-bugs: QTBUG-55449 и QTBUG-55510, которые показывают намерение этой функции. BTW, QTBUG-55510 предоставляется программный обход для настройки Qt-DPI-осведомленности без фиксации Qt.conf
(используйте по своему усмотрению, потому что он использует 'private' классы реализации Qt, которые меняют интерфейс без уведомления с более новой версией Qt).
И вы указали правильный подход к масштабированию в режиме наблюдения за DPI-монитором. К сожалению, кроме того, что в то время не было большой альтернативы. Однако программные способы помочь обработке событий для масштабирования окна, когда он перемещается с одного монитора на другой. Метод типа resizeWidget
(один, не многие) во главе этого вопроса должен быть вызван с использованием чего-то вроде (Windows):
// we assume MainWindow is the widget dragged from one monitor to another
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG* pMsg = reinterpret_cast<MSG*>(message);
switch (pMsg->message)
{
case WM_DPICHANGED:
// parameters TBD but mind that 'last' DPI is in
// LOWORD(pMsg->wParam) and you need to detect current
resizeWidget(monitorRatio());
break;
Это довольно сложный и трудный путь, и я прибегал к тому, чтобы приложение переключалось между режимами System и Per Monitor DPI Aware, позволяя пользователю выбирать режим и перезапускать процесс приложения (либо фиксируя Qt.conf
, либо делая обход из QTBUG-55510 в начале приложения). Наша надежда заключается в том, что компания Qt понимает, что для режима мониторинга DPI необходим режим автоматического масштабирования для виджетов. Зачем нам это нужно (?) - еще один вопрос. В моем случае у меня есть рендеринг для каждого монитора в собственном холсте виджета приложения, который должен быть масштабирован.
Сначала, прочитав комментарий к этому вопросу от @selbie, я понял, что есть способ попытаться установить QT_SCREEN_SCALE_FACTORS во время запуска приложения:
QT_SCREEN_SCALE_FACTORS [список] определяет масштабные коэффициенты для каждого экран. Это не изменит размер шрифтов с размерами точек. Эта переменная окружения в основном полезна для отладки или для работы мониторы с неправильной информацией EDID (расширенная идентификация дисплея Данные).
Затем я прочитал блог Qt о том, как применять множественные факторы экрана, и попытался сделать это ниже для мониторов 4K и 1080p, где первые 4K перечислены первыми (основной).
qputenv("QT_SCREEN_SCALE_FACTORS", "2;1");
Это немного помогает: почти правильный рендеринг, но вводит дефекты с размером окна при перемещении окна с одного монитора на другой, в значительной степени похожим на QTBUG-55449 делает. Думаю, я пойду с подходом WM_DPICHANGED
+ QT_SCREEN_SCALE_FACTORS
, если клиент рассмотрит текущее поведение приложения как ошибку (мы делаем одну и ту же базу для всех мониторов DPI через System DPI Aware). Еще нет готового к использованию решения от Qt.