28

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

 4 years ago
source link: http://www.cnblogs.com/swarmbees/p/12004594.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

DPI发展

随着显示器质量的增高,高分屏逐渐增多,很多用户平时使用的机器都是2k屏甚至是4k屏。

显示器分辨率变大后,同样的物理尺寸下可以表示更多的点,也就是我们平时所说的像素。

误区说明

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

为什么会有这个误区呢?

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

1、PPI

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

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

PPI的始作俑者

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

q6JBvuI.png!web

需要注意的是,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。

2、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一样,可以决定图片打印的物理尺寸。

一、Win自适应系统

High DPI Desktop Application Development on Windows

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

二、Qt机制

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

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

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

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接口

2、 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右键属性-兼容性-所有用户设置进行禁用

3、适配DPI结论

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

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

2、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升级工作。

三、Qt适配

由于升级到5.13有很多成本,暂且使用Qt5.7进行适配

使用Qt5.7适配高DPI

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

决定使用Qt5.7适配高DPI后,我们需要干如下几件事:

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

1、统一比例

100% 200%

2、强制刷新

WM_DPICHANGED

接收系统DPI发生变化消息

3、图片适配

添加不同DPI下图片

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

四、自己适配

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

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

适配项目

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

1、窗口大小

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

setFixedWidth
setFixedHeight
......

动态调整

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

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

2、字体大小

重新生成qss文件

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

3、间距

布局的margin

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

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

padding和margin

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

4、图标

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

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

qss方式

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

自绘

如果是自绘文字图图片,那就需要自己控制缩放比,和图片压缩系数,具体方案下一篇文章讲解


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK