[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);
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
这个函数是用来启用高DPI缩放的。当应用程序在高分辨率的显示设备上运行时,Qt会自动根据系统的DPI设置来缩放界面元素,使得界面在不同分辨率的显示器上具有合适的大小和清晰度。此属性应在创建QApplication对象之前设置。
- QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
这个函数是用来启用高分辨率位图的支持的。当设置为true时,Qt会尝试使用高分辨率版本的位图(如果有的话),以保证在高DPI显示设备上图标和其他图形元素的清晰度。这对于那些使用像素图(如PNG或JPEG图像)作为界面元素的应用程序尤其有用。
难道这样就可以了?
显然只这样做是不够的,如果这样的话,实际上只是启动了Qt程序的DPI支持。你可能会想,那敢情好啊,直接开了DPI支持,是不是就万事大吉了?
答案是错误的,实际上你会遇到三个问题:
- 缩放比例错误
当你尝试缩放的时候,你会发现有时候缩放比例过大,有时候缩放比例又过小,这是为什么呢?
为了解决这个问题,我们需要翻到Qt的文档里面有关这个AA_EnableHighDpiScaling的文章
对于此,你会惊喜的发现,这个自带的DPI设置似乎会自动指向整数,也就是说,你的缩放比例为1.25时,它的缩放比例就会四舍五入变成1,缩放比例到1.5的时候,缩放比例也就会到2,很可能你用的时候就会直接把屏幕给撑爆了。
用户的屏幕默认缩放比例本身就是错的
有时候,特别是有些小的抽象的笔记本,什么动不动十七寸的显示器,分辨率又畸形的高,可能动不动缩放比例就给到2到三,要是程序本身界面就够大,可能直接就给屏幕撑爆了,这是不好的。字体显示异常
正常屏幕上显示
更换了屏幕之后
解决方法
- 为了解决前面两个问题,我们参考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();
}
- 关于字体缩放不当
首先我们要搞清楚有关字体大小的一些设置
我们知道对于Qt来说,他们是很喜欢用Pt这个单位的,几乎所有默认的单位都是Pt,但是实际上又有另外一个单位px,我们需要先搞清楚这两个单位是做什么的
- 点(pt):点是传统的印刷行业使用的度量单位,1点等于1/72英寸。在显示设备上,使用点作为字体大小的单位时,Qt会根据系统的DPI(每英寸点数)设置来调整字体的实际像素大小。例如,在96 DPI的显示器上,1点大约等于1.333像素。使用点作为单位设置字体大小时,字体的大小会根据不同的显示器分辨率自动调整,以保持视觉上的一致性。
- 像素(px):像素是计算机显示领域的一个基本单位,直接对应屏幕上的一个显示点。在Qt中以像素为单位设置字体大小意味着无论DPI设置如何,字体的大小始终以固定的像素数显示。这会导致在不同DPI设置的显示器上,相同像素值的字体大小视觉上可能会有很大差异。
这种自动缩放的目的是确保在高分辨率显示器上元素保持适当的物理大小,从而提升用户体验。然而,这种自动缩放可能导致在不同分辨率和 DPI 设置下,使用点单位设置的字体大小出现视觉上的不一致,因为点单位本身是与物理尺寸(1/72 英寸)相关的,而屏幕 DPI 会影响这一转换关系。
使用 点(pt) 设置字体或大小时,这些设置会根据系统的 DPI 自动缩放,以尝试保持物理上的一致性,从而在高 DPI 显示器上可能看起来过大或过小。
使用 像素(px) 设置时,元素的大小直接映射到屏幕的像素,不会根据 DPI 进行自动调整,因此在高 DPI 设置下可能看起来偏小,因为更多的像素被压缩在了物理尺寸相同的空间内。
[Qt开发]当我们在开发兼容高分辨率和高缩放比、高DPI屏幕的软件时,我们在谈论什么。的更多相关文章
- 笨重的mfc还在基于系统控件,熟练的mfc工程师还比不过学习Qt一个月的学生开发效率高(比较精彩,韦易笑)
作者:韦易笑链接:https://www.zhihu.com/question/29636221/answer/45102191来源:知乎著作权归作者所有,转载请联系作者获得授权. 更新:擦,本来只有 ...
- SQL 横转竖 、竖专横 (转载) 使用Dapper.Contrib 开发.net core程序,兼容多种数据库 C# 读取PDF多级书签 Json.net日期格式化设置 ASPNET 下载共享文件 ASPNET 文件批量下载 递归,循环,尾递归 利用IDisposable接口构建包含非托管资源对象 《.NET 进阶指南》读书笔记2------定义不可改变类型
SQL 横转竖 .竖专横 (转载) 普通行列转换 问题:假设有张学生成绩表(tb)如下: 姓名 课程 分数 张三 语文 74 张三 数学 83 张三 物理 93 李四 语文 74 李四 数学 84 ...
- Dapper.Contrib 开发.net core程序,兼容多种数据库
Dapper.Contrib 开发.net core程序,兼容多种数据库 https://www.cnblogs.com/wuhuacong/p/9952900.html 使用Dapper.Contr ...
- 关于开发APP接口版本不兼容的问题
关于 APP接口版本兼容的问题. iOS和android 要不断开发新版本,很多服务端开发都是在以前接口的逻辑上进行修改. 新的APP和接口开发后,接口如何兼容老的APP? 有的公司 每次发布完APP ...
- 【神经网络与深度学习】【Qt开发】【VS开发】从caffe-windows-visual studio2013到Qt5.7使用caffemodel进行分类的移植过程
[神经网络与深度学习][CUDA开发][VS开发]Caffe+VS2013+CUDA7.5+cuDNN配置成功后的第一次训练过程记录<二> 标签:[神经网络与深度学习] [CUDA开发] ...
- 【Qt开发】【VS开发】【Linux开发】OpenCV、Qt-MinGw、Qt-msvc、VS2010、VS2015、Ubuntu Linux、ARM Linux中几个特别容易混淆的内容
[Qt开发][VS开发][Linux开发]OpenCV.Qt-MinGw.Qt-msvc.VS2010.VS2015.Ubuntu Linux.ARM Linux中几个特别容易混淆的内容 标签:[Qt ...
- 【Qt开发】【Linux开发】Qt程序在嵌入式设备(arm) 上运行,鼠标擦除界面的解决方案
笔者最近想在arm开发板上,开发一个应用程序,经过网上查询发现qt作为跨平台开发软件很不错,于是便选择了qt开发,笔者的qt版本是4.8.6的.由于arm的主频太低,在arm上进行开发编译,效率会大大 ...
- 【Qt开发】【VS开发】VS2010+Qt开发环境搭建
QT与JAVA有点类似,也是一种跨平台的软件(当然在windows平台和linux平台需要安装相应的QT开发环境和运行库,类似于JAVA在不同平台下的虚拟机JVM环境),因此对于某些需要同时支持win ...
- 【大型软件开发】浅谈大型Qt软件开发(一)开发前的准备——在着手开发之前,我们要做些什么?
前言 最近我们项目部的核心产品正在进行重构,然后又是年底了,除了开发工作之外项目并不紧急,加上加班时间混不够了....所以就忙里偷闲把整个项目的开发思路聊一下,以供参考. 鉴于接下来的一年我要操刀这个 ...
- 真正的RISC-V开发板——VEGA织女星开发板开箱评测
前言 由于最近ARM公司要求员工"停止所有与华为及其子公司正在生效的合约.支持及未决约定",即暂停与华为的相关合作,大家纷纷把注意力投向了另一个的处理器架构RISC-V,它是基于精 ...
随机推荐
- Hadoop HDFS 3.2的部署
之前写过HDFS 2.6的部署,最近项目中尝试使用最新的HDFS 3.2.1做离线存储,部署方式略有不同,所以这里再简单写一下,这里只涉及到存储因此不再配置yarn,只配置HDFS最基本的服务Name ...
- vscode使用npm安装依赖报错
1.报错信息 npm ERR! code EPERM npm ERR! syscall open npm ERR! path C:\Node\node_cache_cacache\index-v5\4 ...
- maven报错:501 HTTPS Required
maven报错:501 HTTPS Required 简单来说,如果报错中出现http://repo1.maven.org/maven2/的字样的话,那么大概率就是Maven仓库的设置里的地址有问题, ...
- EasyNLP集成K-BERT算法,借助知识图谱实现更优Finetune
导读 知识图谱(Knowledge Graph)的概念⾸次出现2012年,由Google提出,它作为⼀种⼤规模语义⽹络, 准确地描述了实体以及实体之间的关系.知识图谱最早应⽤于搜索引擎,⽤于准备返回⽤ ...
- 大数据时代下,App数据隐私安全你真的了解么?
简介:你是否有过这样的经历:你和朋友聊天表达你近期想要购买某件商品,第二天当你打开某购物软件时,平台向你推送的商品正是你想要购买的:或者,你是否接到过陌生来电,他们准确的报出了你的名字和年龄.... ...
- 基于 ASK + EB 构建容器事件驱动服务
简介:本篇文章以"在线文件解压场景"为例为大家展示经典 EDA 事件驱动与容器如何搭配使用. 作者:冬岛.肯梦 导读 EDA 事件驱动架构( Event-Driven Archit ...
- Kubernetes 稳定性保障手册:洞察+预案
简介: 稳定性保障是个复杂的话题,需要有效.可迭代.可持续保障集群的稳定性,系统性的方法或许可以解决该问题. 作者 | 悟鹏来源 | 阿里巴巴云原生公众号 <Kubernetes 稳定性保障手册 ...
- Mobius 一个运行在 .NET Core 上的 .NET 运行时
一个 .NET 应用仅仅只是一块在 .NET 运行时上面运行的二进制代码.而 .NET 运行时只是一个能执行这项任务的程序.当前的 .NET Framework 和 .NET Core 运行时采用 C ...
- JavaScript字符串String方法介绍及使用示例
实例方法 charAt() charCodeAt() 返回索引位置的字符 'hello'.charAt(0) //h 等价 'hello'.[0] //返回索引位置的字符的Unicode码点 'hel ...
- selenium项目中遇到的问题总结
问题:在pycharm中运行用例能成功,在命令行运行提示找不到com包解决办法:添加一个PYTHONPATH的环境变量,值为工程目录的路径 当要查找的文本前后有换行时,用如下方法解决//td[cont ...