赞
踩
网上很多代码是用 logicalDotsPerInch 除以 96 来获取屏幕缩放比:
- // 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 类的接口:
- 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 模块:
- QT += core gui widgets
- QT += gui-private
简单的测试:
- 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 中的大致代码就是:
- 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。