Qt之高DPI显示器(一) - 解决方案整理

原文连接:Qt之高DPI显示器(一) - 解决方案整理html

最近一直在处理高DPI问题,也花费了很多功夫,前先后后使用了多种解决方案,各类方案也都有利弊,笔者最终采用了自适配方案,虽然复杂一些,可是结果可控。这里把处理的过程记录下来,留给有一样需求的同窗web

DPI发展

随着显示器质量的增高,高分屏逐渐增多,不少用户平时使用的机器都是2k屏甚至是4k屏。正则表达式

显示器分辨率变大后,一样的物理尺寸下能够表示更多的点,也就是咱们平时所说的像素。shell

误区说明windows

咱们如今平时所说的软件像素应该是PPI(Pixels Per Inch),中文意思是每英寸像素数,而咱们windows系统中修改的DPI其实就是这个PPI。api

为何会有这个误区呢?app

答案:由于这个世界正在尽人类想象所能地使其变得难懂。函数

一、PPI

每英寸像素数,像素表示的是“图片的原色”,足够靠近你显示屏上的图片你就会看到他们:一排一排的小方块。换句话说,他们也是一个电子图片的最小可寻址单元。工具

其中每个电子图片则是由更小的光学单元组成,这些光学单元就是红色、绿色和蓝色。布局

PPI的始做俑者

可悲的是,一些生产厂商将这些 sub-pixel 描述为“dot”,为何这样认为呢?由于他和DPI的墨点工做方式相同,而后就是一顿商业互吹,用DPI来描述PPI就被开始误用了。

须要注意的是,pixel 是一个固定大小的物理物体,所以,一个屏幕上的 PPI 是固定的。大部显示器都是 66 - 130ppi。

PPI 和打印的目标

只有要打印出来时,设定 PPI 才有效。

在打印的过程当中,全部在屏幕上组成图片的物理pixel都被转换成不一样色调的小正方形,这些小正方形是另一种“像素”,下文中都使用pixel-d来表示。

当打印时,若是增长图片的大小为300%,图片是放大了300%,可是图片的颗粒度更大了!若是想要清晰度不变,而大小发生变化,这个时候咱们就须要修改PPI。

看一个图片打印的示例

图片尺寸 PPI 物理春 结果 打印机(DPI) 每英寸点数 总点数 结果
300px * 300px 10 30 * 30英寸 很是大 60 60 * 60 30 * 30 * 每英寸点数 很是虚
300px * 300px 300 1 * 1英寸 很是小 90 90 * 90 1 * 1 * 每英寸点数 细腻
300px * 300px 60 5 * 5英寸 可能合适 120 120 * 120 5 * 5 * 每英寸点数 很是细腻

对于最终的打印输出而言,将 PPI 输入认为是一种调节物理大小的方式,而不是分辨率。

PPI能够决定打印的大小,想要更加细腻的打印效果则是须要增长更多的pixel-d。

二、DPI

DPI 只是打印机的技术参数,就像是你电脑显示器的 pixel 分辨率。

好比说,你以 600 dpi 来打印一幅 150ppi 的图像,那么每一个“pixel”将会包括16个 dot(600 dot/150 “pixel” = 4 x 4 / “pixel”)。

名称 说明
Inch英寸 物理单位,能够衡量显示器的物理大小
PPI每英寸像素数 物理值,由硬件厂商决定。表示每英寸下能够存储多少个光学单元
DPI每英寸点数 打印机单位,一个技术参数,表明打印机的好坏。一般来讲,dot 矩阵打印机可打印的 dpi 范围为 60 - 90,喷墨打印机的 dpi 范围为 300 - 600,而激光打印机为 600 - 1800。
Resolution分辨率 显示器单位,描述每英寸像素数
windows系统DPI 我的理解:windows本身的一个标准,表示每英寸像素数,也就是PPI(显示器真正的PPI不支持修改);相似于打印时的DPI。一个技术指标或者参数

综上:对于咱们软件开发来讲,其实所说的像素大小都是指PPI,这里要区分不是显示器的固定PPI,windows系统上修改DPI时其实修改的系统模拟出来的PPI;就相似于咱们打印图片时输出的PPI同样,能够决定图片打印的物理尺寸。

1、Win自适应系统

High DPI Desktop Application Development on Windows

总的来讲能够用,可是会模糊。目前win10效果最好,基本清晰,可是还能够优化;win7系统上基本是糊的,若是您的产品是一个互联网软件,那么系统自适应绝对不是最佳方案。

2、Qt机制

要使用Qt高DPI缩放,首先得禁用系统缩放。

方式1: QApplication构造前设置Qt::AA_EnableHighDpiScaling属性

方式2: 设置环境变量QT_AUTO_SCREEN_SCALE_FACTOR为1

一、Windows系统DWM缩放

启用系统缩放时,因为使用的都是图片拉伸的方式则会产品模糊

--- DPI Unaware System DPI Awareness Per-Monitor and Per-Monitor (V2) DPI Awareness
含义 启用系统缩放 应用程序已在启动的显示器上支持高DPI,可是没有对其余显示器支持,也就是说请系统在其余显示器上帮我启用系统缩放 永远不要对我作虚拟化,由于我本身能搞定

启用系统DPI虚拟化,能够调用SetProcessDpiAwareness接口。该接口有一个枚举的参数类型PROCESS_DPI_AWARENESS,可是这个参数只有在Win8.1以后才有。

Win10上有一个加强型虚拟化,能够大大优化DWM效果。

Win7能够调用SetProcessDpiAware接口

二、 Qt适配高DPI

基于Qt5.7测试结果

--- Qt虚拟化 推荐度 系统虚拟化 推荐度
Win7 只能使用整数倍放大,效果会模糊 * 支持系统下拉框中的浮点缩放,图片会模糊(有些系统失效) **
Win10 只能使用整数倍放大,字体比较清晰,可是须要适配高DPI图片 **** 图片拉伸,启用了Win加强型DWM,效果还能够,但字体没有Qt适配清楚 **

基于Qt5.13测试结果

--- Qt虚拟化 推荐度 系统虚拟化 推荐度
Win7 同Qt5.7,可是显示有过好于Qt5.7 ** 同Qt5.7 **
Win10 支持系统自定义分辨率,例如125%、175%
在不一样分辨率下分别启动软件后,在相同指定分辨率下显示大小不同
例如:在分辨率125%下启动软件,此时不要关闭程序1并修改分辨率为150%,而后在启动一次软件为程序2,观察程序1和程序2的大小,发现不一大。
**** 同Qt5.7 **

咱们的软件在Win10上会强制启用加强型虚拟户,须要对exe右键属性-兼容性-全部用户设置进行禁用

三、适配DPI结论

一、Qt5.7只支持整数比例缩放

  1. 100%:0-149%
  2. 200%:150%-249%
  3. 300%:250%-349%
  4. ...日后依次类推
  5. 100%DPI下启动程序,切换DPI时没法对已启动软件大小作出影响;反之若是非100%DPI启动程序则是正常的。

二、Qt5.13支持系统预约义缩放比例

  1. 100%:100%
  2. 125%:125%
  3. ...日后依次类推,若是自定义了缩放比,默认按250%(测试结果,不必定准,有待测试多个显示器)显示。但不一样分辨率下启动同一个软件后(启动的软件不关闭切换分辨率),在最后切换的分辨率上观察程序,大小都不同。

Qt5.7和Qt5.13都有的问题

100%DPI启动软件后,再次修改DPI时,软件大小不会再次发生变化。

到这这里高DPI测试基本结束,综合各类状况,得出以下两个结论

  1. 高DPI适配使用Qt来作。Qt支持高DPI比windows系统缩放效果要好。
  2. Qt使用5.7。升级Qt到5.13时,须要升级vs至少到2015,而且软件只能是x64版本的,不然还须要升级工具到更高版本,而且咱们的依赖库也可能须要从新编译,成本较高,并且5.13支持高DPI比5.7多的地方咱们暂时能够不须要(主要是支持系统定义好的浮点缩放),所以不作Qt升级工做。

3、Qt适配

因为升级到5.13有不少成本,暂且使用Qt5.7进行适配

使用Qt5.7适配高DPI

缺点请看一节第三小节中Qt5.7只支持整数比例缩放

决定使用Qt5.7适配高DPI后,咱们须要干以下几件事:

  1. 原生放大比例和web放大比例统一
  2. 系统DPI修改时,禁用刷新
  3. 添加不一样DPI下图片

一、统一比例

100% 200%

二、强制刷新

WM_DPICHANGED

接收系统DPI发生变化消息

三、图片适配

添加不一样DPI下图片

Qt适配完以后仍是存在一些问题,比方说只支持系统已有缩放比,不能支持任意比例缩放,并且有时候还存在刷新问题、软件异常放大等等。

4、本身适配

业务层不须要考虑scale,只须要使用T打头控件开发便可。

注:因为篇幅的缘故,T打头的控件下一篇文章讲解

适配项目

  1. 窗口大小
  2. 字体大小
  3. 间距
  4. 图标

一、窗口大小

重写顶层窗口设置界面大小函数

setFixedWidth
setFixedHeight
......

动态调整

记录调用了哪些设置大小的函数,在dpi发生变化时从新设置一遍

if (testflag("setfixedWidth"))
{
    setFixedWidth(width * scale);
}

二、字体大小

从新生成qss文件

读取原有qss文件,使用正则表达式生成scale版本的新qss文件。

三、间距

布局的margin

记录调用了哪些设置大小的函数,在dpi发生变化时从新设置一遍,相似于窗口大小变化时所做调整

if (testflag("margin"))
{
    setContextMargin(...);
}

padding和margin

读取原有qss文件,使用正则表达式生成scale版本的新qss文件。

四、图标

工程中须要添加1x 2x 3x等不一样分辨率的图标,1x图标为正常状况下使用的图标,2x和3x图标分别是高分辨率下的图标

替换图标有两种状况,一种是使用qss方式贴图,另外一种是自绘贴图

qss方式

预先生成高分辨率下的整数倍xxx_2x.qss和xxx_3x.qss文件,实际使用的时候在动态调整,具体方案下一篇文章讲解

自绘

若是是自绘文字图图片,那就须要本身控制缩放比,和图片压缩系数,具体方案下一篇文章讲解

5、参考文章

PPI vs. DPI: 有什么区别?

High DPI Desktop Application Development on Windows

PROCESS_DPI_AWARENESS Enumeration

SetProcessDPIAware function:Win Vista开始支持的接口

SetProcessDpiAwareness function:Win8.1开始支持的接口

关于Windows高DPI的一些简单总结

如何开发新的Qt 5.7高DPI每监视器DPI感

值得一看的优秀文章:

  1. 财联社-产品展现
  2. 广联达-产品展现
  3. Qt定制控件列表
  4. 牛逼哄哄的Qt库

若是您以为文章不错,不妨给个 打赏,写做不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!




很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权全部,转载时请用连接的方式,给出原文出处。同时写上原做者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时经过修改本文达到有利于转载者的目的。

相关文章
相关标签/搜索