gpt4 book ai didi

c++ - 如何着手开发新的 Qt 5.7+ High-DPI Per Monitor DPI Aware 应用程序?

转载 作者:IT老高 更新时间:2023-10-28 23:01:09 41 4
gpt4 key购买 nike

我看过官方Qt documentation以及 StackOverflow 上关于 Qt 中高 DPI 支持的许多文章和问题。他们都专注于移植旧的应用程序并让它们以尽可能少的更改工作。

但是,如果我要启动一个全新的应用程序,并打算支持每个显示器的 DPI 感知应用程序,那么最好的方法是什么?

如果我理解正确,Qt::AA_EnableHighDpiScaling 与我想要的完全相反。我实际上应该禁用 HighDpiScaling 并在运行时手动计算所有尺寸?

许多建议说根本不使用尺寸,而是使用 float 布局。但在许多情况下,至少需要存在最小宽度和/或最小高度。由于 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 应用程序?

最佳答案

If I were to start a brand new application, with the intention to support per-monitor DPI awareness, what is the best approach?

我们不依赖 Qt 在每显示器 DPI 感知模式下进行自动缩放。至少设置了 Qt::AA_EnableHighDpiScaling 的基于 Qt 5.7 的应用程序不会这样做,并且无论像素密度如何,“高 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=.

If I understand correctly, Qt::AA_EnableHighDpiScaling is the very opposite of what I want. I should actually disable HighDpiScaling and calculate all the dimensions manually on runtime?

不,这不是相反的东西,而是不同的东西。有几个 Qt 错误已作为无错误关闭:QTBUG-55449QTBUG-55510显示该功能背后的意图。顺便说一句,有QTBUG-55510提供了一种编程解决方法,用于在不修复 qt.conf 的情况下设置 Qt DPI 感知(自行决定使用,因为它使用“私有(private)”Qt 实现类来更改接口(interface),而不会通知较新的 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;

这是一个相当困难和麻烦的方法,我通过让用户选择模式并重新启动应用程序进程(修复 qt. conf 或在应用程序启动时从 QTBUG-55510 执行解决方法)。我们希望 Qt 公司意识到需要针对小部件自动缩放的每显示器 DPI 感知模式。为什么我们需要它(?)是另一个问题。在我的情况下,我在自己的应用小部件 Canvas 中进行了每个显示器的渲染,应该可以缩放。

起初,阅读@selbie 对这个问题的评论,我意识到也许有一种方法可以在应用启动时尝试设置 QT_SCREEN_SCALE_FACTORS:

QT_SCREEN_SCALE_FACTORS [list] specifies scale factors for each screen. This will not change the size of point sized fonts. This environment variable is mainly useful for debugging, or to work around monitors with wrong EDID information(Extended Display Identification Data).

然后我读到 Qt blog关于如何应用多个屏幕因素并尝试对 4K 和 1080p 显示器执行以下操作,其中 4K 排在首位(主要)。

qputenv("QT_SCREEN_SCALE_FACTORS", "2;1");

这确实有点帮助:几乎正确的渲染但是在将窗口从一个监视器移动到另一个监视器时引入了窗口大小的缺陷,就像 QTBUG-55449做。如果客户将当前的应用程序行为视为错误(我们通过 System DPI Aware 为所有显示器 DPI 创建相同的基础),我想我会使用 WM_DPICHANGED + QT_SCREEN_SCALE_FACTORS 方法。 Qt 还没有现成可用的解决方案。

关于c++ - 如何着手开发新的 Qt 5.7+ High-DPI Per Monitor DPI Aware 应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39823918/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com