Как подойти к разработке нового приложения Qt 5.7+ High-DPI на монитор DPI?
Я прочитал официальный документации Qt и многие статьи и вопросы по StackOverflow о высокой поддержке DPI в Qt. Все они сосредоточены на портировании старых приложений и их работе с как можно меньшими изменениями.
но если я должен был начать совершенно новое приложение, с намерением поддерживать на мониторе DPI aware app, каков наилучший подход?
Если я правильно понял, то Qt::AA_EnableHighDpiScaling
является полной противоположностью того, что я хочу. Я должен фактически отключить HighDpiScaling и вычислить все измерения вручную во время выполнения?
многие из предложений говорят, что не использовать размеры вообще, использовать плавающие макеты. Но во многих случаях желательно иметь хотя бы минимальную ширину и/или минимальную высоту. Поскольку Qt Designer позволяет мне помещать значения только в абсолютные пиксели, каков правильный подход? Куда поместить код для пересчета измерений при изменении разрешения монитора?
или я должен просто идти с автоматическое масштабирование?
мое решение из предыдущего приложения Qt (не проверено)
в одном из моих старых приложений, где я пытался добавить поддержку HighDPI, я использовал этот подход - список всех детей DOM и изменить их размер по одному заданному соотношению. Ratio = 1 даст размеры, равные тем, которые я указал в Qt Designer.
void resizeWidgets(MyApp & qw, qreal mratio)
{
// ratio to calculate correct sizing
qreal mratio_bak = mratio;
if(MyApp::m_ratio != 0)
mratio /= MyApp::m_ratio;
// this all was done so that if its called 2 times with ratio = 2, total is not 4 but still just 2 (ratio is absolute)
MyApp::m_ratio = mratio_bak;
QLayout * ql = qw.layout();
if (ql == NULL)
return;
QWidget * pw = ql->parentWidget();
if (pw == NULL)
return;
QList<QLayout *> layouts;
foreach(QWidget *w, pw->findChildren<QWidget*>())
{
QRect g = w->geometry();
w->setMinimumSize(w->minimumWidth() * mratio, w->minimumHeight() * mratio);
w->setMaximumSize(w->maximumWidth() * mratio, w->maximumHeight() * mratio);
w->resize(w->width() * mratio, w->height() * mratio);
w->move(QPoint(g.x() * mratio, g.y() * mratio));
}
foreach(QLayout *l, pw->findChildren<QLayout*>())
{
if(l != NULL && !(l->objectName().isEmpty()))
layouts.append(l);
}
foreach(QLayout *l, layouts) {
QMargins m = l->contentsMargins();
m.setBottom(m.bottom() * mratio);
m.setTop(m.top() * mratio);
m.setLeft(m.left() * mratio);
m.setRight(m.right() * mratio);
l->setContentsMargins(m);
l->setSpacing(l->spacing() * mratio);
if (l->inherits("QGridLayout")) {
QGridLayout* gl = ((QGridLayout*)l);
gl->setHorizontalSpacing(gl->horizontalSpacing() * mratio);
gl->setVerticalSpacing(gl->verticalSpacing() * mratio);
}
}
QMargins m = qw.contentsMargins();
m.setBottom(m.bottom() * mratio);
m.setTop(m.top() * mratio);
m.setLeft(m.left() * mratio);
m.setRight(m.right() * mratio);
// resize accordingly main window
qw.resize(qw.width() * mratio, qw.height() * mratio);
qw.setContentsMargins(m);
qw.adjustSize();
}
который вызывается из main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyApp w;
// gets DPI
qreal dpi = a.primaryScreen()->logicalDotsPerInch();
MyApp::resizeWidgets(w, dpi / MyApp::refDpi);
w.show();
return a.exec();
}
Я не считаю это хорошим решением. Учитывая, что я начинаю все заново, и я ... может полностью настроить мой код на последние стандарты Qt, какой подход я должен использовать для получения приложений HighDPI?
1 ответов
если бы я начал совершенно новое приложение, с намерением поддержка осознания DPI на мониторе, каков наилучший подход?
мы не полагаемся на Qt для автоматического масштабирования в режиме DPI на мониторе. По крайней мере, Qt 5.7-приложение с Qt::AA_EnableHighDpiScaling
set этого не делает, и "высокое масштабирование DPI" является более точным рисунком независимо от плотности пикселей.
и для вызова режима DPI на мониторе вам нужно изменить в тот же каталог, в котором вы проецируете исполняемый файл:
[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=.
QTBUG-55449 и QTBUG-55510 которые показывают намерение за чертой. Кстати, есть QTBUG-55510 программный обходной путь для установки осведомленности Qt DPI без фиксацииесли я правильно понимаю, Qt:: AA_EnableHighDpiScaling является очень совсем не то, что я хочу. Я должен фактически отключить HighDpiScaling и вычислить все измерения вручную во время выполнения?
qt.conf
предоставляется (используйте по своему усмотрению, потому что он использует "частные" классы реализации 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;
это довольно сложный и хлопотный способ пойти, и я прибегнул, чтобы позволить приложению переключаться между системами и режимами монитора DPI, позволяя пользователю выбирать режим и перезапускать процесс приложения (либо фиксируя qt.conf
или делать решение от QTBUG-55510 при запуске приложения). Наша надежда заключается в том, что компания Qt понимает, что существует необходимость в режиме DPI для каждого монитора с автоматическим масштабированием для виджетов. Зачем нам это нужно?) это другой вопрос. В моем случае у меня есть рендеринг на монитор в собственном холсте виджета приложения, который должен быть масштабирован.
сначала, читая комментарий к этому вопросу от @selbie, я понял, что, возможно, есть способ попытаться установить QT_SCREEN_SCALE_FACTORS в то время как приложение начинается:
QT_SCREEN_SCALE_FACTORS [list] задает масштабные коэффициенты для каждого экран. Это не изменит размер шрифтов точечного размера. Этот переменная среды в основном полезна для отладки или для работы мониторы с неправильной информацией EDID(Расширенная идентификация дисплея Данные.)
Я тут прочитала Qt blog о том, как применить несколько факторов экрана и попытаться сделать следующее для мониторов 4K и 1080p, где 4K список первый (основной).
qputenv("QT_SCREEN_SCALE_FACTORS", "2;1");
это немного помогает: почти правильный рендеринг но вводит дефекты с размером окна при перемещении окна с одного монитора на другой, как QTBUG-55449 делает. Думаю, я пойду с WM_DPICHANGED
+ QT_SCREEN_SCALE_FACTORS
подход, если клиент считает текущее поведение приложения ошибкой (мы делаем ту же базу для всех мониторов DPI через System DPI Aware). Еще нет готового к использованию решения от Qt.