首页 > 其他分享 >[Qt开发]当我们在开发兼容高分辨率和高缩放比、高DPI屏幕的软件时,我们在谈论什么。

[Qt开发]当我们在开发兼容高分辨率和高缩放比、高DPI屏幕的软件时,我们在谈论什么。

时间:2024-06-07 16:23:54浏览次数:15  
标签:Qt 缩放 像素 设置 屏幕 DPI

前言

最近在开发有关高分辨率屏幕的软件,还是做了不少尝试的,当然我们也去网上查了不少资料,但是网上的资料也很零碎,说不明白,这样的话我就做个简单的总结,希望看到这的你可以一次解决你有关不同分辨率下的所有问题。

分辨率?DPI?

首先我们搞清楚我们现在到底面对的是什么场景。在开发高分屏的时候,实际上不仅仅是分辨率高,其附带 的推荐缩放比例往往也会相应的变化

在这里插入图片描述
这个两个数值会直接影响你程序的显示效果,例子我就不举了,关于什么是DPI,什么是分辨率,我这里简单说说

我们假设现在我们开发的软件界面大小是 1000 x 1000,现在测试用的的屏幕都是27寸的屏幕,但是A屏幕是1080p的,即1920x1080,而B屏幕是4K的,即4096×3112,

在这里插入图片描述
看,同样是1000x1000的界面,在1920 x 1080的屏幕上几乎要铺满一大半还要多了,但是在4096x3122的屏幕上,它的宽甚至只占屏幕的1/4。

这就会导致,同样的画面,在1080p的屏幕下显示正常,但是在4k的屏幕上显示就会非常小,小到看不见。

那你可能就要问了,那有没有更好的办法来决定我们的显示呢?


随着屏幕技术的发展,现在高分辨率的屏幕越来越常见了,所以为了解决这个同样大小的程序在不同分辨率下差距过大的问题,Windows引入了一个叫做DPI的概念(Dot per Inch),这个之前打csgo的朋友可能一下就反应过了,是的,鼠标同样有DPI这个概念,而且屏幕DPI和鼠标DPI概念差不多。

DPI指的是图像每英寸(1 英寸 = 25.4 毫米)长度内的像素点数。我们还是应该把像素理解为小方块,dpi就可以理解为是一英寸长度内排列的像素数。通过图像的dpi我们就可以计算出在这个图像中像素的边长,如果也知道图像的分辨率(宽高像素数),就可以知道该图像的真实尺寸了。

当你在Windows的显示设置中调整缩放比例(例如,125%、150%、175%等),实际上是在调整系统级别的DPI设置。这个缩放比例直接影响到系统如何渲染所有的图形用户界面元素,包括字体、图标和整个应用程序窗口。

计算公式如下:

\(实际DPI=基础DPI * \frac{缩放百分比}{100}\)

\(96DPI * 1.5 = 144DPI\)

还有一个概念,点距(dot pitch),就是把像素理解为点的时候,点距就是两个像素点的距离

我们把像素理解为小方块,那点距其实就是像素的边长

点距与DPI之间转换,点距一般用毫米表示,DPI表示1英寸(也就是25.4mm)长度内的像素数,所以点距(像素的边长)就等于 25.4 / DPI(总长度/个数=每个长度)

怎么做

当然了,你肯定对公式不感兴趣,那么我们自然是要说一下怎么解决的。

先说Qt有几个常用的属性。

    //// 启用高DPI缩放
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    // 使用高分辨率的位图(可选)
    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
  1. QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

这个函数是用来启用高DPI缩放的。当应用程序在高分辨率的显示设备上运行时,Qt会自动根据系统的DPI设置来缩放界面元素,使得界面在不同分辨率的显示器上具有合适的大小和清晰度。此属性应在创建QApplication对象之前设置。

  1. QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);

这个函数是用来启用高分辨率位图的支持的。当设置为true时,Qt会尝试使用高分辨率版本的位图(如果有的话),以保证在高DPI显示设备上图标和其他图形元素的清晰度。这对于那些使用像素图(如PNG或JPEG图像)作为界面元素的应用程序尤其有用。

难道这样就可以了?

显然只这样做是不够的,如果这样的话,实际上只是启动了Qt程序的DPI支持。你可能会想,那敢情好啊,直接开了DPI支持,是不是就万事大吉了?

答案是错误的,实际上你会遇到三个问题:

  1. 缩放比例错误
    当你尝试缩放的时候,你会发现有时候缩放比例过大,有时候缩放比例又过小,这是为什么呢?

为了解决这个问题,我们需要翻到Qt的文档里面有关这个AA_EnableHighDpiScaling的文章
在这里插入图片描述
对于此,你会惊喜的发现,这个自带的DPI设置似乎会自动指向整数,也就是说,你的缩放比例为1.25时,它的缩放比例就会四舍五入变成1,缩放比例到1.5的时候,缩放比例也就会到2,很可能你用的时候就会直接把屏幕给撑爆了。

  1. 用户的屏幕默认缩放比例本身就是错的
    有时候,特别是有些小的抽象的笔记本,什么动不动十七寸的显示器,分辨率又畸形的高,可能动不动缩放比例就给到2到三,要是程序本身界面就够大,可能直接就给屏幕撑爆了,这是不好的。

  2. 字体显示异常
    正常屏幕上显示
    在这里插入图片描述
    更换了屏幕之后
    在这里插入图片描述

解决方法

  1. 为了解决前面两个问题,我们参考Qt.io上的文档
    High-DPI Support in Qt 5.6

在这里插入图片描述
哇,没想到这个缩放比例可以直接由环境变量设置,那我们就可以将这个缩放比例的环境变量设置为 N/1080,这样我们的程序就会在运行的过程中始终保持其在画面中的比例,而不需要关心比例和分辨率了。

注:你可能想用Qt自带的QScreen去检查屏幕分辨率,但是QScreen不能在QApplication初始化之前使用,但是设置缩放比例又必须在QApplication初始化之前进行,所以

具体操作代码如下:

#include <QApplication>
#include <QDebug>
#include <QString>

RECT RetrieveMonitorBounds(int idx) {
    DISPLAY_DEVICEW dd;
    dd.cb = sizeof(dd);
    BOOL flag = EnumDisplayDevicesW(nullptr, idx, &dd, 0);

    DEVMODEW dm;
    dm.dmSize = sizeof(dm);
    dm.dmDriverExtra = 0;
    flag = EnumDisplaySettingsExW(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm, 0);

    RECT rect = { dm.dmPosition.x, dm.dmPosition.y, dm.dmPosition.x + dm.dmPelsWidth, dm.dmPosition.y + dm.dmPelsHeight };
    return rect;
}

int main(int argc, char* argv[]) {
    int monitorCount = ::GetSystemMetrics(SM_CMONITORS);
    qDebug() << "Detected monitors: " << monitorCount;
    QString scalingFactors;

    for (int j = 0; j < monitorCount; ++j) {
        RECT dimensions = RetrieveMonitorBounds(j);
        int h = dimensions.bottom - dimensions.top;
        double scale = (h > 1080) ? (double)h / 1080.0 : 1.0;
        scalingFactors += (j == 0 ? "" : ";") + QString::number(scale, 'f', 1);
    }

    QByteArray envVar = scalingFactors.toUtf8();
    qputenv("QT_SCREEN_SCALE_FACTORS", envVar);

    // Enable high DPI scaling
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    // Optionally use high resolution pixmaps
    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);

    QApplication app(argc, argv);
    QMainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

  1. 关于字体缩放不当
    首先我们要搞清楚有关字体大小的一些设置

我们知道对于Qt来说,他们是很喜欢用Pt这个单位的,几乎所有默认的单位都是Pt,但是实际上又有另外一个单位px,我们需要先搞清楚这两个单位是做什么的

  1. 点(pt):点是传统的印刷行业使用的度量单位,1点等于1/72英寸。在显示设备上,使用点作为字体大小的单位时,Qt会根据系统的DPI(每英寸点数)设置来调整字体的实际像素大小。例如,在96 DPI的显示器上,1点大约等于1.333像素。使用点作为单位设置字体大小时,字体的大小会根据不同的显示器分辨率自动调整,以保持视觉上的一致性。
  1. 像素(px):像素是计算机显示领域的一个基本单位,直接对应屏幕上的一个显示点。在Qt中以像素为单位设置字体大小意味着无论DPI设置如何,字体的大小始终以固定的像素数显示。这会导致在不同DPI设置的显示器上,相同像素值的字体大小视觉上可能会有很大差异。

这种自动缩放的目的是确保在高分辨率显示器上元素保持适当的物理大小,从而提升用户体验。然而,这种自动缩放可能导致在不同分辨率和 DPI 设置下,使用点单位设置的字体大小出现视觉上的不一致,因为点单位本身是与物理尺寸(1/72 英寸)相关的,而屏幕 DPI 会影响这一转换关系。

使用 点(pt) 设置字体或大小时,这些设置会根据系统的 DPI 自动缩放,以尝试保持物理上的一致性,从而在高 DPI 显示器上可能看起来过大或过小。

使用 像素(px) 设置时,元素的大小直接映射到屏幕的像素,不会根据 DPI 进行自动调整,因此在高 DPI 设置下可能看起来偏小,因为更多的像素被压缩在了物理尺寸相同的空间内。

标签:Qt,缩放,像素,设置,屏幕,DPI
From: https://www.cnblogs.com/Leventure/p/18237406

相关文章

  • Vue3等比例缩放图片组件
    本文由ChatMoney团队出品有些情况我们需要在各种刁钻的情况下都要保持图片比例不变,比如用户缩放窗口等改变布局的情况。实现原理就是通过容器的宽度和内边距在保持你想要的比例。以下是基础功能的组件示例:<template><divstyle="position:relative":style="ratioStr"......
  • PyQT5之菜单栏和工具栏
    fromPyQt5importQtWidgetsfromPyQt5importQtCore,QtGuiimportsysimportcv2classButtonPanel(QtWidgets.QWidget):def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)select_btn=QtWidgets.QPushButton("图......
  • 在线安装 qt 下载安装慢以及安装报错无法下载存档 not found——解决方式
    一、下载安装QT的在线下载器可以在QT官网下载开源的安装包(需要登陆)或者在各大大学的镜像站中下,比如:mirrors.nju.edu.cn(可选)解压出下载的压缩包,拿到qt-unified-windows-x64-online.exe/dmg/run本体在终端中,输入./包名--mirrorhttps://mirror.nju.edu.cn/qt后......
  • 单个python文件代码的车牌检测系统 使用pyqt做界面进行车牌检测,可以保存结果到excel文
    融合了hyperlpr3和opencv来检测车牌通过图片检测车牌的系统,使用了pyqt和hyperlpr3结合来进行检测,可以保存检测的结果到excel文件 亲自测试修改代码,运行正常并且不依赖百度网络api,纯本地运行,融合了2个车牌检测模型,第一个模型使用opencv来模糊图像,然后进行边缘检测和......
  • YOLOv8-PyQT5可视化界面
    使用PyQT5实现YOLOv8图形化界面准备工作:1、首先在YOLOv8环境中安装pyqt5pipinstallpyqt5pipinstallpyqt5-tools然后再你的anaconda环境中找到designer.exe文件,双击运行,可以将其发送到桌面快捷方式方便后续使用下面是我的文件所在路径地址,根据自己环境的位置进行查找。......
  • 在 Ubuntu 环境下 Qt Creator 无法使用搜狗输入法
    在Ubuntu环境下QtCreator无法使用搜狗输入法在Ubuntu中安装QtCreator后,发现无法使用搜狗输入法。切换输入法也没有效果。最初以为是搜狗输入法出了问题,后来发现是QtCreator的问题,需要将搜狗输入法的插件库文件放到Qt的目录下。解决步骤如下:安装locate命令......
  • QT 关于pcl::oncatenateFields的报错问题
    报错类不能是其自身的基类因为pcl::concatenateFields与PointXYZRGB不兼容viewer.reset(newpcl::visualization::PCLVisualizer("viewer",false));vtkNew<vtkGenericOpenGLRenderWindow>window;window->AddRenderer(viewer->getRendererCollection()-&g......
  • Qt中图表图形绘制类介绍
    接上篇介绍QChart相关的类,本片主要在QChart载体上进行图表图形绘制使用各种形状的图类。一.QXYSeries类QXYSeries类是QLineSeries折线图,QSplineSeries样条曲线图,QScatterSeries散点图的基类;QXYSeries类的使用都可以参考下面详细介绍的折线图,样条曲线图,散点图等的应用。......
  • Qt QLineEdit设置数据的输入范围QIntValidator和QDoubleValidator
    在日常开发过程中QLineEdit作为输入框,有时要限制输入的内容,比哪,考试分数为1-100,这个时候就使用QIntValidator作为限制范围,而如何输入的是带小数的呢,那么使用QDoubleValidator可以吗,下面请看具体的示例。1.限制输入的最初使用的是正则表达式1QRegExpregIntExp("^(([1-9][0......
  • Qt 正则表达式 QRegularExpression
    正则表达式QRegularExpression学习在Qt中有两种和正则相关的类,一种是QRegExp类,今天查资料说的好像是从Qt4传承下来的,BUG相对来说比较多,目前基本已停止维护了,多用于正则匹配,还有一种就是今天要讲的QRegularExpression类,是Qt5新开辟出来的类,相对来说比较完善(网上这......