QT-Windows高分屏适配

1,779 阅读2分钟

背景

  1. 在不同的分辨率和缩放比例下,对客户端的UI进行适配
  2. 使用qt版本5.15.3
  3. 使用qt画板.ui进行界面布局

适配方案

方案1

交由Windows进行处理

创建 qt.conf 文件,并添加到 .qrc 资源文件中

qt.conf 文件内容

[Platforms]  
WindowsArguments = dpiawareness=0

方案2

由qt进行接管

需要5.14之后才支持

QCoreApplication::SetAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::SetAttribute(Qt::AA_UseHighDpiPixmaps);

会进行四舍五入,整数倍缩放。即

100% <= scale < 150% 按 100% 缩放

150% <= scale < 250% 按 200% 缩放

以此类推...

未能符合实际想要的根据屏幕设置的实际 scale 等比缩放

原因:存在默认的缩放策略 round 会对比例进行四舍五入

QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy:Round);

HighDpiScaleFactorRoundingPolicy 的枚举下有多中策略可以选择,其中 PassThrough 是根据实际屏幕设置的 scale 值进行等比缩放

注意点

  1. 上述高分屏适配代码需要添加到应用初始化之前
int main(int argc, char *argv[]) {
    // 高分屏适配
    ...
    QApplication application();
    ...
}

开发中遇到的问题和解决办法

修改桌面分辨率之后,不能同步刷新应用

解决方案:在所有屏幕添加DPI变动的信号槽

// 获取所有屏幕
QList<QScreen *> screens = QApplication::screens();

// 遍历屏幕对象添加信号槽
...
    connect(screen, &QScreen::logicalDotsPerInchChanged, this, &MainWindow::OnLogicalDotsPerInchChanged);
...

// 槽函数实现
void MainWindow::OnLogicalDotsPerInchChanged(qreal dpi) 
{
    // 获取当前应用位置
    QPoint point = QPoint(this->screen()->geometry().x(), this->screen()->geometry().x());
    // 遍历screen,获取应用所在位置screen进行应用刷新
    for (auto &screen : QApplication::screens()) {
        if (QApplication::screenAt(point)->name() == screen->name()) {
            update();
        }
    }
}

多个不同dpi的屏幕之间来回拖动,超过边界时,可能会出现异常放大

系统进行了DWM虚拟化处理,可能出现计算错误的情况

解决方案:在 QApplication 初始化之前调用 windows 函数

SetProcessDPIAware();

参考Windows文档

setProcessDPIAware 函数 (winuser.h) - Win32 apps | Microsoft Learn

遗留问题

屏幕缩放比例在放大时,如何实现应用缩放比例最大值的限制? 例如电脑屏幕缩放比例300%时,限制应用比例为250%

windows下跨屏幕(不同分辨率)计算位置问题解决方式

github.com/qtdevs/Fram…