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

qt,dpi · 浏览次数 : 0

小编点评

前言 最近在开发有关高分辨率屏幕的软件,遇到了不少问题。为了简化这些问题,本文将总结一些关键知识点,希望能帮助您一次解决所有不同分辨率下的问题。 分辨率与DPI 首先要明确的是,分辨率和DPI(每英寸点数)是两个不同的概念。分辨率是指显示设备上的像素数量,而DPI是指每英寸上的像素数量。这两个值会直接影响程序的显示效果。 例如,在1080p分辨率的屏幕上,1000x1000的界面大小在视觉上占据的空间会比4K屏幕上的更大。因此,在设计软件界面时,需要考虑DPI的变化来确保在不同分辨率下都有良好的显示效果。 Windows引入了DPI的概念来解决这个问题。通过调整系统级别的DPI设置,可以改变程序中图形用户界面元素的大小和清晰度。 解决方法 要在Qt中实现高DPI缩放,可以使用以下属性: `QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);` `QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);` 这两个属性分别用于启用高DPI缩放和使用高分辨率位图。 然而,仅仅启用DPI支持并不能完全解决问题。还需要注意以下两个问题: 1. 缩放比例错误:有时,根据环境变量设置的缩放比例可能会导致缩放比例不准确。为了避免这个问题,可以将环境变量设置为屏幕的当前缩放比例(96DPI*1.25 ≈ 120DPI)。 2. 字体显示异常:在高DPI显示器上,使用点(pt)单位设置的字体可能会看起来过大或过小。为了避免这个问题,可以将字体单位更改为像素(px),这样就不受DPI影响。 结语 总之,要在高分辨率屏幕上开发软件,需要了解分辨率和DPI的区别,并正确设置QApplication的属性以实现高DPI缩放。同时,还需要注意缩放比例和字体显示的问题,以确保软件在不同分辨率和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屏幕的软件时,我们在谈论什么。相似的内容:

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

前言 最近在开发有关高分辨率屏幕的软件,还是做了不少尝试的,当然我们也去网上查了不少资料,但是网上的资料也很零碎,说不明白,这样的话我就做个简单的总结,希望看到这的你可以一次解决你有关不同分辨率下的所有问题。 分辨率?DPI? 首先我们搞清楚我们现在到底面对的是什么场景。在开发高分屏的时候,实际上不

QGIS开发笔记(二):Windows安装版二次开发环境搭建(上):安装OSGeo4W运行依赖其Qt的基础环境Demo

前言 使用QGis的目的是进行二次开发,或者说是融入我们的应用(无人车、无人船、无人机),本片描述搭建QGis二次基础开发环境,由于实在是太长了,进行了分篇: 上半部分:主要是安装好后,使用QtCreator可以使用QGIs的apps下的Qt使用对应的编译器编译不带qgis的空工程。 下半部分:在上

QGIS开发笔记(三):Windows安装版二次开发环境搭建(下):将QGis融入QtDemo,添加QGis并加载tif遥感图的Demo

前言 使用QGis的目的是进行二次开发,或者说是融入我们的应用(无人车、无人船、无人机),本片描述搭建QGis二次基础开发环境,由于实在是太长了,进行了分篇: 上半部分:主要是安装好后,使用QtCreator可以使用QGIs的apps下的Qt使用对应的编译器编译不带qgis的空工程。 下半部分:在上

Qt-qrencode开发-生成、显示二维码

将qrencode使用Qt封装为一个生成、显示二维码的控件; 支持使用QPainter绘制显示二维码; 可通过函数接口返回生成的二维码QImage; 可通过调用函数将生成的二维码保存到指定路径; 支持使用源码嵌入工程(更好的跨平台、支持各种编译器); 支持使用编译好的静态库(MSVC2017-64)...

QtCreator 跨平台开发添加动态库教程(以OpenCV库举例)- Windows篇

Qt具有跨平台的特性,即Qt数据结构与算法库本身跨平台和编译脚本(.pro)跨平台。在同时具有Windows下和Linux开发的需求时,最好的建议是使用QtCreator来开发,虽然也可以使用其他的IDE配合CMake等方式,但使用QtCreator更加方便,并且操作环境完全一致。QtCreator

硬件开发笔记(二十一):外部搜索不到的元器件封装可尝试使用AD21软件的“ManufacturerPart Search”功能

前言 这是一个AD的一个强大的新功能,能招到元器件的原理图、3D模型还有价格厂家,但是不一定都有,有了也不一定有其3D模型。 ManufacturerPart Search 在设计工具中选择即用型元件 直接搜索,搜索到需要使用的元器件。在Altium Designer中,直接选中设备元件。无需使用第

硬件开发笔记(十九):Altium Designer 21软件介绍和安装过程

前言 AD硬件设计软件之一,前面说了allego,但是allego对项目的管理、原理图生成PCB,PCB反向原理图等方面比较复杂,对于一般的硬件(非多个高速电路),选择AD能够加大的节省开发工作量。 本篇介绍AD21、AD21较20新增的高效功能和其安装过程。 Altium Designer 21

硬件开发笔记(十八):核心板与底板之间的连接方式介绍说明:板对板连接器

前言 核心板与底板之间的连接方式至少就有四种以上,包括且不限于:DIP直插、板对板连接器、邮票孔和金手指。 常用连方式介绍 DIP直插 DIP就是以前的元器件封装,直接DIP插入焊接,宿便找了个,如下图: 可以定制自己的,一般来说,没有高速电路问题不大,但是这种方式对于复杂的底板可能布线就比较麻烦,

Qt开发技术:Q3D图表开发笔记(四):Q3DSurface三维曲面图颜色样式详解、Demo以及代码详解

前言 qt提供了q3d进行三维开发,虽然这个框架没有得到大量运用也不是那么成功,性能上也有很大的欠缺,但是普通的点到为止的应用展示还是可以的。 其中就包括华丽绚烂的三维图表,数据量不大的时候是可以使用的。 前面介绍了基础的q3d散点图、柱状图、三维曲面图,本片深入对三维曲面图支持的颜色表现方式进行探

[Cmake Qt]找不到文件ui_xx.h的问题?有关Qt工程的问题,看这篇文章就行了。

前言 最近在开发一个组件,但是这个东西是以dll的形式发布的界面库,所以在开发的时候就需要上层调用。 如果你是很懂CMake的话,ui_xx.h的文件目录在 $ 下 然后除了有关这个ui_xx.h,还有一些别的可以简单聊聊的 一、父子工程组织,或者说依赖关系 在使用CMake进行开发的时候,一般可以