在实际开发中,我们经常看到如下代码段:

void QtWidgetsApplication1::copyWnd()
{qreal dpr = window()->windowHandle()->devicePixelRatio();QPixmap pixmap(this->size() * dpr);pixmap.setDevicePixelRatio(dpr);...... // 其它代码
}

其中QtWidgetsApplication1为QtWidgets的子类。这里的devicePixelRatio()函数有什么作用呢?

先摘录一个来自知乎网友提供的一个例子:

作者:暮成雪
链接:https://www.zhihu.com/question/40506180/answer/623203881
来源:知乎

我们以mac的发展史来说明什么是物理分辨率,以及为什么需要衍生出逻辑分辨率。

我们的主人公是乔帮主和比尔盖茨。此时乔帮主面前有一台mac,屏幕的分辨率是1280*720,这就是物理分辨率。乔帮主对比尔盖茨说,给我的mac开发一个word软件吧。盖茨说OK,于是写了一个软件,这个软件显示的时候长度是1280像素,宽度是720像素,正好能够盖满整个mac屏幕。乔帮主看了之后很满意。

有一天,乔帮主看自己的mac屏幕觉得很粗糙,一点都不清晰锐利。于是聪明的乔帮主想到,同样是15寸的屏幕,我把像素点翻倍,不就可以更清晰了吗?于是他把mac的物理分辨率改成了2560*1440的分辨率,相当于每个像素点的尺寸减少了4倍(保持原来每个像素占据的面积不变,放了4个像素,这每个像素占据的面积是原来像素占据面积的1/4),这下再也看不出颗粒感了,乔帮主很满意。但是,当乔帮主打开盖茨给他写的word的时候,傻眼了,原本全屏的word现在只占屏幕的四分之一,而且文字非常的小。乔帮主打电话给盖茨说,你的软件怎么出问题了?盖茨回答说,我开发的时候你的mac分辨率就是1280*720,你自己改了硬件尺寸怪我咯,我很忙没空给你改软件代码,你就凑合着用吧。乔帮主稍作思考,马上想出了一个非常聪明的主意!他在软件和硬件之间的系统层加了一层逻辑分辨率。虽然屏幕横向有2560个像素点,但是告诉软件我只有1280个像素点!当word的宽度要占1280个像素的时候,实际上已经占了2560个像素。于是我们的word又占满屏幕了!于是乔帮主把这个机智的想法命名为逻辑分辨率,不管我显示器的硬件有多少个像素点,我只会告诉软件我的逻辑分辨率,这样软件的代码就不用修改也能在不同的屏幕上显示效果一致。在多年后,mac的物理分辨率已经达到了5120 x 2880,但是告诉软件的时候还是说我的分辨率1280*720,相当在盖茨看来的一个逻辑像素点,背后实际上已经有16个物理像素点为其工作了!

 物理像素与逻辑像素相关概念:

关键词:

  物理像素pp(physical pixel)

  逻辑像素/设备独立像素dip(Device Independent Pixels)

  设备像素比dpr(Device Pixel Ratio)

  每英寸像素数ppi(pixel per inch)

  每英寸点数dpi (Dots Per Inch)

像素密度pd(Pixel  density)

(1)物理像素(physical pixel)
        物理像素又被称为设备像素(pp),他是显示设备中一个最微小的物理部件。一个设备的物理像素是固定不变的。见过街上那些走红字的 LED 显示屏么?上面的那一颗颗的 LED 灯就是这块屏幕的发光点,一块LED显示屏宽高有几寸是在生产的时候就被定好的,而宽高各能容纳下多少颗像素,也是在生产的时候就被定好的,这就是我们说的物理像素。每个像素可以根据操作系统设置自己的颜色和亮度。

所谓的一倍屏、二倍屏(Retina)、三倍屏,指的是设备以多少物理像素来显示一个CSS像素,也就是说,多倍屏以更多更精细的物理像素点来显示一个CSS像素点,在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

(2)CSS像素/逻辑像素/设备独立像素/设备无关像素(Device Independent Pixels)

这几个像素的名称其实是指同一个概念,设备独立像素(又称设备无关像素 Device Independent Pixels),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素,Qt界面中的像素),然后由相关系统转换为物理像素。

(3)设备像素比(Device Pixel Ratio, DPR):一个设备的物理像素与逻辑像素之比

设备像素比 (dpr)= 物理像素(pp) / 设备独立像素(dip)

在Retina屏的iphone上,devicePixelRatio的值为2,也就是说1个css像素相当于2个物理像素。通常所说的二倍屏(retina)的dpr是2, 三倍屏是3。  该值也是QWindow类devicePixelRatio函数返回的值。

(4)每英寸像素数ppi(pixel per inch)

就是每1英寸有多少个像素。px就是表示pixel,像素是屏幕上显示数据的最基本的点。px是一个点,它不是自然界的长度单位,谁能说出一个“点”有多长多大么?可以画的很小,也可以很大。如果点很小,那画面就清晰,我们称它为“分辨率高”,反之,就是“分辨率低”。所以,“点”的大小是会“变”的,也称为“相对长度”。在计算机窗体、图像、页面等呈现给对象中,所有的“大”“小”概念,都是基于“屏幕”这个“界面”上。“屏幕”上的各种信息,包括文字、图片、表格等等,都会随屏幕的分辨率变化而变化,一个100px宽度大小的图片,在800×600分辨率下,要占屏幕宽度的1/8,但在1024×768下,则只占约1/10。所以如果在定义字体大小时,使用px作为单位,那一旦用户改变显示器分辨率从800到1024,用户实际看到的文字就要变“小”(自然长度单位),甚至会看不清,影响浏览。

(5)每英寸点数dpi(dots per inch)

pt就是point,是印刷行业常用单位,等于1/72英寸。因此就有这样的说法,pixel是相对大小,而point是绝对大小。在Windows里,默认显示设置中,把文字定义为96DPI,即每英寸 96个点。(微软都将DPI和PPI混为一体,我们也就无须较真了)。这样的定义,说明了:1px=1/96英寸。联系pt的概念,1pt=1/72英寸,可以得出,在这样的设置中,1px=0.75pt,常见的宋体9pt=12px。在显示器分辨率不变的基础上(比如现在常用的1024×768),1px大小也就固定不变,改变显示设置,调整为144DPI,可以得出,1px=0.5pt,常见的宋体9pt=18px。原先用12px来组成的一个文字,现在需要18px来组成,px多了,文字就“大”了,更易阅读了。所以,px和pt的使用区别,只有当用户改变默认的96DPI下才会产生:使用px定义文字,无论用户怎么设置,都不会改变大小;使用pt定义文字,当用户设置超过96DPI的值,数值越大,字体就越大。

(6) 像素密度pd(Pixel  density)

屏幕像素密度(pd)是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素(ppi)或每英寸多个点(dpi)来衡量的。屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。

屏幕像素密度(ppi) = 对角线分辨率 / 对角线尺寸

我们平时所说的屏幕尺寸一般是指屏幕对角线的尺寸,而不是指屏幕的长或高。

代码分析:

通过前文的描述,前面代码:

第3行:返回显示器像素(物理像素)和窗体像素(逻辑像素)的比值dpr。即用dpr个物理像素点绘制Qt窗体中的1个像素点,dpr在默认情况下为1,只有在高清屏才会大于1。本句代码中的window()返回本窗体的QWindow对象,而window()->windowHandle()则返回QWindow对象的native widget对象。关于QWidget的parentWidget、window、nativeParent窗体的概念及用法,请参考:《QWidget的parentWidget、window、nativeParentWidget区别与理解》。

第4行:QPixmap类对象pixmap设置其尺寸为当前窗体尺寸的dpr倍,按理说此时pixmap会比窗体尺寸大dpr倍,但实际不是这样。这是因为Qt内部的基于QPixmap类的布局器在计算布局时会将dpr考虑进来,从而导致pixmap几何布局按下面公式计算:

layoutSize = pixmap.size() / pixmap.devicePixelRatio()

即还是原来的没有乘以dpr的大小。也就是说这么多物理像素还是得在原来pixmap尺寸大小的地方显示,假如dpr大于1,则必然在pixmap原来只显示1个像素的地方要显示dpr个像素,这样会导致pixmap显示更高清,因为原来1个像素占据的地方被dpr个像素占据显示了,这就是Qt实现高清屏采用的技术。

总结:

  • devicePixelRatio函数获取高清屏下每个逻辑像素对应几个物理像素,即绘制一个逻辑像素需要用到几个物理像素。
  • 诸如setDevicePixelRatio之类的函数,就是告知QPainters对象,在被绘制的目标上用几个物理像素来绘制1个逻辑像素。

参考链接:

【1】:https://www.zhihu.com/question/40506180/answer/623203881

【2】:物理像素与逻辑像素相关概念 - 剑仙6 - 博客园 (cnblogs.com)

QWindow类devicePixelRatio函数作用相关推荐

  1. C++ 笔记(16)— 类和对象(类定义、类实例对象定义、访问类成员、类成员函数、类 public/private/protected 成员、类对象引用和指针)

    1. 类的定义 类定义是以关键字 class 开头,后跟类的名称.并在它后面依次包含类名,一组放在 {} 内的成员属性和成员函数,以及结尾的分号. 类声明将类本身及其属性告诉编译器.类声明本身并不能改 ...

  2. Effective C++ 类与函数设计和申明

    Effective C++ 类与函数的设计和申明 在看<Effective C++>这本书的过程中,我无数次的发出感叹,这他妈写得太好了,句句一针见血,直接说到点上.所以决定把这本书的内容 ...

  3. 10.2 运算符重载函数作为类成员函数和友元函数

    Complex operator+(Complex &c2) { Complex c; c.real=real+c2.real; c.imag=imag+c2.imag; return c; ...

  4. c语言静态变量存在堆还是栈,c 类 static 函数 什么样是静态变量?嵌入式C语言的堆栈管理如何实现...

    C语言中静态变量是什么意思,有什么作用,static在数据类型前面表示什么 最近刚看了C存储类的章节.所以来说说. C语言为变量提供了⑤种不同的存储模型,或者说是存储类. ①个变量可以用存储时期描述, ...

  5. 关于类成员函数中访问同类对象的私有成员

    关于类成员函数中访问同类对象的私有成员,主要包含以下几种场景: a. 在C++的类的成员函数中,允许直接访问该类的对象的私有成员变量. b. 在类的成员函数中可以访问同类型实例的私有变量. c. 拷贝 ...

  6. C++static类静态成员函数及变量解析

    类静态成员作用,无论创建多少个实例,类静态成员只有一个副本,即不会被销毁,除非程序运行结束. 类静态成员只能单独定义,无法在构造函数中定义类静态成员 类静态成员访问的话 只能通过类静态函数访问 类静态 ...

  7. python嵌套类(内部类相互调用)_核心解密Python函数在(类与函数之间)和(类与类之间)互相调用...

    image.png 一.类与函数之间 首先来看一个函数间的调用 类方法: #实现类中函数之间互相调用 #下面一个学生的简单自我介绍为例子 __metaclass__=type #自由的.动态的修改/增 ...

  8. Lua注册C++类及函数

    本文版权归 csdn whitehack 所有,转载请自觉标明原创作者及出处,以示尊重!! 作者:whitehack 出处:http://blog.csdn.net/whitehack/article ...

  9. API各函数作用简介

    API各函数作用简介 1.控件与消息函数 AdjustWindowRect 给定一种窗口样式,计算获得目标客户区矩形所需的窗口大小  AnyPopup 判断屏幕上是否存在任何弹出式窗口  Arrang ...

最新文章

  1. stm32双向可控硅调压程序_单向可控硅和双向可控硅的测量与模块测试
  2. appium python框架结构,GitHub - wyybingo/python-appium: 基于PageObject UI自动化测试框架,支持Android/iOS...
  3. SAP QM 事务代码QPR3显示一个Physical Sample Record
  4. jQuery 表单验证插件,jQuery Validation Engine用法详解
  5. Oracle实现数据增删改的sql语句实例
  6. springboot调用python脚本_Springboot实现上传文件接口,使用python的requests进行组装报文上传文件的方法...
  7. html5图像映射坐标怎么看,如何将AxesImage中的坐标映射到已保存图像文件中的坐标?...
  8. [mybatis]缓存_缓存原理图
  9. jquery地图插件jvectorMap
  10. inurl news.php id,news.php
  11. STM32CubeMX官网下载方法
  12. yolov5环境配置-Anaconda3 + Pytorch1.8 + Cuda10.2 + cuDnn8.2.0 + opencv3.2.0
  13. C#将DataGridView中的数据导出为EXCEL
  14. fmri 分析数据 fsl spm 两大平台比对
  15. 关于色域与BT.2020相关学习心得笔记
  16. 计算机网络安全基础的上机知识,网络安全上机竞赛试题操作演示.pdf
  17. c语言填空题带答案,C语言练习题-填空题(带答案)
  18. Bootstrap里的圆角outline
  19. 1176: 【入门】买蛋糕
  20. 3dmax入门教程(一)

热门文章

  1. 【正则表达式】判断是否为名字
  2. 工作经费的开支范围_工会经费开支范围
  3. Ubuntu系统修改主机名和用户名
  4. pytorch炼金术-DataSet-PASCAL VOC 简介
  5. 大学记忆(1)[记忆之殇]
  6. 小米路由器开ssh方法
  7. 教培机构如何实现长期主义知识变现?
  8. 关于unity游戏进程的问题:退出,锁屏,被杀掉等事件
  9. 学习笔记07渲染路径+阴影
  10. Vbox虚拟机安装GHOSTXP蓝屏提示processr.sys,错误代码0x000000CE