Qt获取屏幕DPI缩放比

获取屏幕缩放比

网上很多代码是用 logicalDotsPerInch 除以 96 来获取屏幕缩放比:

cpp 复制代码
// Windows 除以 96,macOS 除以 72
qreal factor = window->screen()->logicalDotsPerInch() / 96.0;

当使能了缩放适配后,logicalDotsPerInch 值就不随系统缩放变了:

复制代码
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    // Qt6 默认开启缩放
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif

如果是 PassThrough 支持小数的设置,此时可以用 QScreen 的 devicePixelRatio 获取缩放比。

很明显,我们需要更通用的方式。通过查看源码,发现其实 Qt 内部是有对应接口的,比如 QHighDpiScaling 类的接口:

cpp 复制代码
qreal QHighDpiScaling::rawScaleFactor(const QPlatformScreen *screen)
{
    // Determine if physical DPI should be used
    static const bool usePhysicalDpi = qEnvironmentVariableAsBool(usePhysicalDpiEnvVar, false);

    // Calculate scale factor beased on platform screen DPI values
    qreal factor;
    QDpi platformBaseDpi = screen->logicalBaseDpi();
    if (usePhysicalDpi) {
        QSize sz = screen->geometry().size();
        QSizeF psz = screen->physicalSize();
        qreal platformPhysicalDpi = ((sz.height() / psz.height()) + (sz.width() / psz.width())) * qreal(25.4 * 0.5);
        factor = qreal(platformPhysicalDpi) / qreal(platformBaseDpi.first);
    } else {
        const QDpi platformLogicalDpi = QPlatformScreen::overrideDpi(screen->logicalDpi());
        factor = qreal(platformLogicalDpi.first) / qreal(platformBaseDpi.first);
    }

    return factor;
}

其中 usePhysicalDpi 一般我们也用不到,所以可以直接用 else 部分的逻辑。不过这里用到了 QPlatformScreen 类,需要引入 gui-private 模块:

cpp 复制代码
QT += core gui widgets 
QT += gui-private

简单的测试:

cpp 复制代码
void MainWindow::calcDpi()
{
    // 可以从 QWidget 或者 QWindow 拿到 QScreen 对象
    QScreen *cur_screen = this->screen();
    qDebug()<<__FUNCTION__<<cur_screen;
    if (cur_screen) {
        // 逻辑 dpi (logicalBaseDpi().first) 默认值 win 96/ mac 72
        const QDpi base_dpi = cur_screen->handle()->logicalBaseDpi();
        const QDpi logic_dpi = QPlatformScreen::overrideDpi(cur_screen->handle()->logicalDpi());
        // 得到屏幕缩放百分比
        const qreal factor = qreal(logic_dpi.first) / qreal(base_dpi.first);
        qDebug()<<"calc dpi"<<factor;
    }
}

关联屏幕设置变化

当在多个屏幕拖动,或者修改当前屏幕缩放比后,我们需要重新获取缩放比。

QWindow 提供了 screenChanged 信号可以感知屏幕切换。

QScreen 提供了 physicalDotsPerInchChanged 和 logicalDotsPerInchChanged 信号可以感知分辨率变化。

在 Widgets 中的大致代码就是:

cpp 复制代码
void MainWindow::initWindow()
{
    qDebug()<<this->winId();
    // 构造的时候 windowHandle 还未初始化,可以等 show 的时候关联,或者先调用一次 winId
    connect(this->windowHandle(), &QWindow::screenChanged, this, &MainWindow::onScreenChange);
    calcDpi();
}

void MainWindow::onScreenChange(QScreen *screen)
{
    // QMetaObject::Connection 保存连接便于释放;
    if (logicalDpiConnection) {
        disconnect(physicalDpiConnection);
        disconnect(logicalDpiConnection);
    }
    if (screen) {
        // 切换缩放比时,EnableHighDpiScaling 会触发 physicalDotsPerInchChanged
        // 此时 Qt6 不触发 logicalDotsPerInchChanged
        physicalDpiConnection = connect(screen, &QScreen::physicalDotsPerInchChanged, this, &MainWindow::calcDpi);
        logicalDpiConnection = connect(screen, &QScreen::logicalDotsPerInchChanged, this, &MainWindow::calcDpi);
        calcDpi();
    }
}

void MainWindow::calcDpi()
{
    // 可以从 QWidget 或者 QWindow 拿到 QScreen 对象
    QScreen *cur_screen = this->screen();
    qDebug()<<__FUNCTION__;
    if (cur_screen) {
        // 逻辑 dpi (logicalBaseDpi().first) 默认值 win 96/ mac 72
        const QDpi base_dpi = cur_screen->handle()->logicalBaseDpi();
        const QDpi logic_dpi = QPlatformScreen::overrideDpi(cur_screen->handle()->logicalDpi());
        // 得到屏幕缩放百分比
        const qreal factor = qreal(logic_dpi.first) / qreal(base_dpi.first);
        qDebug()<<"calc dpi"<<factor;
    }
}

完成示例代码:

QWidget 获取 DPI 缩放:https://github.com/gongjianbo/MyTestCode/tree/master/Qt/TestQt_20231221_Dpi

QML 获取 DPI 缩放:

https://github.com/gongjianbo/MyTestCode/tree/master/Qml/TestQml_20231221_Dpi

相关推荐
誰能久伴不乏5 小时前
【Qt实战】工业级多线程串口通信:从底层协议设计到完美收发闭环
linux·c++·qt
liu****5 小时前
4.Qt窗口开发全解析:菜单栏、工具栏、状态栏及对话框实战
数据库·c++·qt·系统架构
从此不归路10 小时前
Qt5 进阶【11】图形视图框架:用 QGraphicsView 搭一个流程图编辑器
开发语言·c++·qt
凯子坚持 c10 小时前
Qt常用控件指南(7)
服务器·数据库·qt
wkd_00712 小时前
【Qt | QTableWidget】QTableWidget 类的详细解析与代码实践
开发语言·qt·qtablewidget·qt5.12.12·qt表格
残梦531413 小时前
Qt6.9.1起一个图片服务器(支持前端跨域请求,不支持上传,可扩展)
运维·服务器·开发语言·c++·qt
mengzhi啊14 小时前
QT的语言家使用方法示范
qt
Henry Zhu12314 小时前
Qt网络编程详解(下):项目实战
网络·qt
轩情吖15 小时前
Qt布局管理器
开发语言·c++·qt·布局管理器·桌面级·qvboxlayout·qhboxlayout
CSDN_RTKLIB15 小时前
Qt Creator中修改源文件编码
qt