我已经阅读了有关Qt中高DPI支持的StackOverflow上的官方Qt文档和许多文章和问题.所有这些都专注于移植旧应用程序并使它们尽可能少地进行更改.
但是如果我要开始一个全新的应用程序,打算支持每个监视器的DPI感知应用程序,最好的方法是什么?
如果我理解正确,Qt::AA_EnableHighDpiScaling
则与我想要的完全相反.我应该实际禁用HighDpiScaling并在运行时手动计算所有尺寸?
许多建议都表示不使用尺寸,使用浮动布局.但是在许多情况下,希望存在至少最小宽度和/或最小高度.由于Qt Designer只允许我将值放在绝对像素中,所以正确的方法是什么?如果显示器分辨率发生变化,我应该在何处放置代码重新计算尺寸?
或者我应该选择自动缩放?
在我尝试添加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();
}
Run Code Online (Sandbox Code Playgroud)
从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();
}
Run Code Online (Sandbox Code Playgroud)
我认为这不是一个好的解决方案.鉴于我正在重新开始,我可以完全自定义我的代码到最新的Qt标准,我应该使用什么方法来获取HighDPI应用程序?
Ale*_*r V 11
如果我要开始一个全新的应用程序,旨在支持每个监视器的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=.
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,Qt :: AA_EnableHighDpiScaling与我想要的完全相反.我应该实际禁用HighDpiScaling并在运行时手动计算所有尺寸?
不,这不是对立面而是另一回事.有几个Qt错误被关闭为无错误:QTBUG-55449和QTBUG-55510显示了该功能背后的意图.顺便说一下,QTBUG-55510提供了一个程序化的解决方法,用于设置Qt DPI意识而不进行修复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;
Run Code Online (Sandbox Code Playgroud)
这是一个非常困难和麻烦的方法,我通过让用户选择模式并重新启动应用程序进程(在QTBUG-55510处修复qt.conf
或执行解决方法)来启用应用程序以在系统和Per Monitor DPI Aware模式之间切换.应用程序开始).我们希望Qt公司意识到需要为每个监视器DPI识别模式以及小部件的自动扩展.我们为什么需要它(?)是另一个问题.在我的情况下,我在自己的应用程序小部件画布中有每个监视器渲染,应该缩放.
首先,从@selbie阅读这个问题的评论我意识到在应用程序启动时可能有一种方法尝试设置QT_SCREEN_SCALE_FACTORS:
QT_SCREEN_SCALE_FACTORS [list]指定每个屏幕的比例因子.这不会改变点大小字体的大小.此环境变量主要用于调试,或用于处理具有错误EDID信息(扩展显示标识数据)的监视器.
然后,我读了Qt博客,了解如何应用多个屏幕因素,并尝试在4K和1080p监视器中执行以下操作,其中4K首先列出(主要).
qputenv("QT_SCREEN_SCALE_FACTORS", "2;1");
Run Code Online (Sandbox Code Playgroud)
这确实有点帮助:几乎正确的渲染,但引入了窗口大小的缺陷,同时将窗口从一个监视器移动到另一个监视器,就像QTBUG-55449一样.如果客户将当前的应用程序行为视为错误(我们通过系统DPI Aware为所有监视器DPI建立相同的基础),我想我将采用WM_DPICHANGED
+ QT_SCREEN_SCALE_FACTORS
方法.仍然没有准备好使用Qt的解决方案.
归档时间: |
|
查看次数: |
4051 次 |
最近记录: |