怎么查看网站是asp还是php,杭州网站建设开发有限公司,在哪个平台做网站好,wordpress链接浏览量如果没有特殊的处理#xff0c;Qt的UI窗口在不同的分辨率和缩放率下#xff0c;其显示效果可能会出现问题#xff0c;常见的有#xff1a; 子控件堆叠#xff0c;无法显示完整 窗口尺寸变大#xff0c;超出屏幕的显示范围 控件变形#xff0c;长宽比不合理 界面模糊 …如果没有特殊的处理Qt的UI窗口在不同的分辨率和缩放率下其显示效果可能会出现问题常见的有 子控件堆叠无法显示完整 窗口尺寸变大超出屏幕的显示范围 控件变形长宽比不合理 界面模糊 字体变大控件尺寸却没有变化 有两种方式可以对UI界面进行良好的缩放 Qt不做任何事情由windows系统负责缩放 windows系统不做任何事情由Qt负责进行缩放
1.解决方案Windows适配
使用qt.conf在资源qrc里添加:/qt/etc/qt.conf, qt.conf文件内容为[Platforms][Platforms]
WindowsArguments dpiawareness0这样的效果就是直接让windows来接管和控制缩放。它通过类似缩放图片这样的方式来实现界面缩放好处是各种情况下界面都可以使用而且子界面不至于变形坏处是放大后界面会变得模糊。
2.解决方案Qt适配Qt5.6版本及以后
如果只是想单纯地解决问题而不想深入了解高DPI的相关原理那么只需知道对应的操作即可。
想要Qt适配不同分辨率和缩放率即可以在高DPI下正常显示我们需要做如下的工作
2.1 开启支持高DPI的属性
在Qt5.6以及后续的版本中添加了对高DPI显示的支持这个特性默认是关闭的需要我们手动打开这个特性注意以下代码必须在main函数中实例化QApplication对象之前调用否则是不会起效果的 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);以上代码做了三件事情分别是 开启Qt对高DPI显示的支持 开启Qt对高分辨率版本pixmapHigh resolution versions of pixmaps的支持 设置对高DPI也就是大于1的DPI值值的四舍五入规则 第一个没什么好说的打开这个开关Qt才会启动对高DPI特性适配的功能 第二个在后续会解释相关概念和原理本节会介绍如何使用这个特性。 第三个需要解释一下当设置高DPI的时候我们假设它的值为 originDPI它是一个大于等于1的浮点数常见取值有1.01.251.51.752.0 等等具体取决于操作系统中的设置。而Qt提供了一个机制让我们决定是否采用这个原始值也就是可以对原始值进行舍入的操作实际使用的是舍入后的值即实际应用的DPI值。 在网络上很多关于讲解Qt适配不同分辨率和缩放比的文章中都会提到Qt仅支持整数倍的DPI值这是错误的因为它们没有修改对DPI的射入政策使用的默认值为Qt::HighDpiScaleFactorRoundingPolicy::Round它会将小数点后大于等于 0.5 的部分取整因此结果如下
window下设置的缩放比Qt实际应用的缩放比100%1x125%1x150%2x175%2x200%2x225%2x250%3x
而Qt::HighDpiScaleFactorRoundingPolicy::PassThrough这个策略则不会对原始值做任何修改他会直接使用所以实际的缩放比和设置的缩放比是完全一样的。
2.2 图片对高DPI的支持
当UI被放大的时候原本的图片会显得比较模糊这是因为同一张的图片被显示到了更大的物理矩形框中导致的。
为了解决这个问题我们需要开启Qt对高分辨率版本pixmapHigh resolution versions of pixmaps的支持然后按照如下策略提供图片资源。
2.2.1 外部图片
QImageReader类负责读取图片资源它提供了自动识别并读入高分辨率版本pixmap的功能。例如我们在DPI为1.0时需要一个20x20的图片它的路径为 :/icons/basename.png 。当DPI为2时这个图片实际显示的尺寸就会被拉伸为原来的两倍显示就会变得模糊。为了解决这个问题我们应该提供这个图片的高分辨率版本pixmap
:/icons/basename.png
:/icons/basename2x.png
:/icons/basename3x.png
:/icons/basename4x.png其尺寸分别为20x20,40x40,60x60,80x80。 QImageReader会根据当前的DPI设置自动读取对应版本的pixmap然后设置其devicePixelRatio属性为DPI值。例如上面的代码在DPI为1时读取:/icons/basename.png图片devicePixelRatio为1.0当DPI为2时读取:/icons/basename2x.pngdevicePixelRatio为2.0依次类推。 这样通过在不同DPI时应用不同的图片事实上在qt底层会使用这些整数倍的图片进行缩放获取当前dpi缩放率对应的高分辨率版本pixmap就不会有图片模糊的情况发生。 qss中设置的图片支持这样的机制。
但要注意的是如果使用的是QPixmap则并非如此它不会自动读取对应dpi的图片。 例如 QPixmap pix(:/icons/basename.png);那么在任何情况下无论dpi的值是多少它读取的都是:/icons/basename.png而不是其他图片。 QIcon类型查看文档它是一个提供了可缩放图标的类型也就是说QIcon没有size这个说法要使用它时先给定一个size将其转化为QPixmap然后才能使用。 QIcon在构造时会根据dpi自动读取对应的图片。假如我们提供了上面的四张图片那么当dpi为1的时候它仅读取1倍图当dpi为1.251.51.752.0 时它会读取1倍图2倍图当dpi大于2小于3时会读取1倍图2倍图3倍图。也就是说QIcon只读取它当前可能会用到的图用不到的图不会读取。另外要注意QIcon是根据图片名称来读取的例如basename.png实际是3倍图那么它仍然读取的是这个图。是根据名称而不是其他来读取图片的。 此时可以使用 QIcon::availableSizes()来返回它读取的图片列表的尺寸尺寸的顺序对应1倍图2倍图3倍图这样的顺序。 QIcon::pixmap() 函数传入指定的size返回一个pixmap。pixmap的尺寸和传入的size可能不同可能相同。大概规则如下
未开启Qt::AA_UseHighDpiPixmaps当size小于QIcon::availableSizes()中的最大尺寸时pixmap的大小为size否则pixmap的大小为QIcon::availableSizes()中的最大尺寸开启了Qt::AA_UseHighDpiPixmaps,此时这个函数会获取dpi的scale缩放系数然后尝试获取 sizescale 尺寸的pixmap是否允许的规则和上述类似如果 sizescale 小于QIcon::availableSizes()中的最大尺寸时pixmap的大小为 size*scale devicePixelRatio为scale否则pixmap的大小为QIcon::availableSizes()中的最大尺寸devicePixelRatio则是一个未知的值。
所以如果想要获取一个图片对应当前dpi的高分辨率版本pixmap代码如下
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); const QString path C:\\Users\\mech-mind_xpp\\Desktop\\icon.png;QSize size(22, 22);
#if 1QIcon icon(path); // 实际应存在1倍图2倍图3倍图// size最好是一倍图的尺寸或等比例缩小的尺寸例如11x11其他情况后果自负auto pxm icon.pixmap(size); ui-svg-setPixmap(pxm);
#elseQPixmap pxm(path); //icon.png实际为三倍图或者其他N倍图qreal pixelRatio qApp-devicePixelRatio();pxm pxm.scaled(size * pixelRatio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);pxm.setDevicePixelRatio(pixelRatio);ui-svg-setPixmap(pxm);
#endif2.2.2 自绘制图片
在UI中使用的图片有些是自己通过代码绘制得来的和从外部读取的图片一样也会有模糊的问题。此时就必须通过一定的策略来让自己绘制的图片成为高分辨率版本pixmap。
其关键点如下 图片的尺寸和DPI相关 QPixmap或者其他图片类设置 devicePixelRatio属性值为DPI的值 由于图片的尺寸会随着DPI变化因此实际绘制的细节中所使用的尺寸也都需要跟着DPI变化。由于DPI是一个浮点数所以QPainter应该尽量使用那些参数为qreal的重载函数。 代码梗概如下
QSize size6464
qreal dpi window()-devicePixelRatioF();QPixmap pix(size * dpi);
pix.setDevicePixelRatio(dpi);QPainter painter(pix);
... ...事实上自绘制的图片和从外部读取的图片其要点是完全一样的。
2.2.3 另一种选择
以上是Qt提供的非常正规的办法但缺点是每个图标都需要提供多张图片会导致app的尺寸变得更大。一种比较偏门的办法是直接提供一张N倍图例如3倍图或者4倍图。比如当显示效果为20x20那么我们可以提供一个尺寸为60x60的图片3倍图或者80x80的图片4倍图。这样即使是在高DPI下图片显示仍然是清晰的这是因为将大尺寸的图片缩小后设置给了控件因此避免了模糊的问题同时资源文件的大小也不会变得太大算是一种折中的办法。
接下来说明这种做法的具体操作细节
2.2.3.1 qss使用border-image而不是image
假设现在有一个图标我们的本意是想将它作为20x20的图标使用。但为了解决模糊的问题现在给了一个3倍图是60x60。此时如果使用qss设置图片那么我们应该使用border-image而不是image这是因为image默认并不会缩放图片而是使用图片的原始尺寸所以实际并不能表现为20x20的效果而是60x60而border-image则是会进行缩放填满控件范围因此不需要担心尺寸问题反而因为是大尺寸图片渲染到小尺寸可以解决图片模糊的问题。
2.2.3.2 QLabel设置图片
还是上面的问题QLabel默认的属性scaleContents是false此时如果设置一个pixmapQLabel会缩放自身的size来使用pixmap的尺寸。而为了解决模糊的问题应该反过来给QLabel设置尺寸设置属性scaleContents为true然后设置pixmap。 label-setFixedSize(20,20);label-setScaledContents(true);label-setPixmap(QPixmap(:/icons/back.png)); // back.png的尺寸为60x60但需要注意的是此时不能将pixmap进行缩放操作然后再设置给label这样由于从大尺寸图片缩小为了小尺寸就丢失了图片的细节仍然不能解决图片模糊的问题 label-setFixedSize(20,20);label-setScaledContents(true);QPixmap pix QPixmap(:/icons/back.png); // back.png的尺寸为60x60pix pix.scaled(QSize(20,20)); //错误这样和直接给一个20x20的图片是一样的仍然会模糊label-setPixmap(pix); 2.2.3.3 QPainter绘制图片
在代码中有时候会使用QPainter绘制图片这种操作也会导致图片模糊。还是上面的情况由于QPainter的drawPixmap不会缩放图片它使用的是pixmap的原始尺寸所以绘制出来是60x60的大小而如果提前将pixmap进行scale操作和2.2.3.2中一样图片仍然会模糊此时我们应该按照**高分辨率版本pixmap **的逻辑来解决这个问题 注意pixmap的dpr最好和当前dpi的设置一致。否则可能会出现图片变形的问题。
QPixmap pix(:/icons/back.png); // back.png的尺寸为60x60
QSize size(20,20);
qreal pixelRatio qApp-devicePixelRatio();
pix pix.scaled(size * pixelRatio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
pix.setDevicePixelRatio(pixelRatio);QPainter painter;
painter.drawPixmap(...);2.3 其他注意事项
QPainter中应该尽量使用qreal类型的重载函数。 这是因为当dpi为1.251.5这样的值时对应的尺寸也必须跟着scale倍数放大如果参数是整数类型那么可能会因为丢失小数部分而不能体现scale效果如有必要可以根据屏幕的尺寸也就是分辨率以及dpi的倍数来调整window和dialog的大小尽量不要给控件设置固定尺寸而是通过QSizePolicy给定一个弹性的尺寸范围然后使用layout自适应窗口尺寸的变化
2.3.1 高DPI下窗口尺寸超出屏幕范围
在100%的缩放率下窗口的宽度为 width x height那么在大于100的缩放率下就会有 width * scale 大于 屏幕分辨率宽度 或者 height * scale 大于 屏幕分辨率高度的情况。这种情况下建议将 width 和 height 的值修改为当前屏幕支持的最大值或者直接showMax或者ShowFullScreen 。 注意上面说的屏幕支持的最大值为screenSize.width() / dpi 。例如当前缩放率为200%屏幕分辨率为1920x1080那么此时如果窗口不想超出屏幕那么支持的最大宽高为960x540. 示例代码
void showEvent(QShowEvent* event) override
{auto dlgSize this-size();const qreal scale window()-screen()-devicePixelRatio();const auto screenSize window()-screen()-size();dlgSize dlgSize * scale;qDebug() ....scale scale;if (dlgSize.width() screenSize.width() || dlgSize.height() screenSize.height()) {// setFixedWidth(screenSize.width() / scale);// setFixedHeight(screenSize.height() / scale);// showMaximized();showFullScreen();}QDialog::showEvent(event);
}然而在很多情况下窗口的尺寸并不能随意变化。例如某些窗口要维持一定的长宽比否则就不好看或者将高度或者宽度缩小后由于其中的子控件设置了固定尺寸而导致子控件堆叠等等。 所以尽量不要设置固定尺寸使用layout管理子控件让窗口可以自适应size的变化这是非常重要的。对于UI设计人员来讲也应该尽量克制自己对细节的追求尽量不要使用例如指定固定尺寸严格指定控件位置等等这种只适合静态布局的方法而是要考虑到窗口尺寸变化时子控件跟随变化的合理性。
3.控件堆叠与Unable to set geometry问题
在实际中会发生子控件堆叠不能显示完全的问题或者报警告Unable to set geometry等。
发生这两种情况的根本原因就是父窗口的尺寸不足以容纳全部子窗口或者即使能容纳子窗口之间也会非常拥挤甚至发生堆叠显示不完全。
解决这个问题的思路大致分为两种 动态设置window的尺寸而不是设置固定尺寸 可以调用adjustSize()函数让window自动按照内容调节大小根据当前分辨率和缩放率调整window的尺寸 使用QScrollArea管理子控件 为了让window拥有可以调节尺寸的能力这就要求各个子控件的尺寸是可调节的或者大多数子控件的尺寸是可调节的因此控件的尺寸只要不要设置为固定尺寸而是通过QSizePolicy设置为可调节的这样当window窗口需要放大或者缩小时layout才能适应这样的尺寸变化。
4. DPI基本概念
首先我们了解两个概念 Dots per inch (DPI)每英寸点数 Device-independent pixel (DIPs)独立于设备像素设备自由像素 DPI这个概念最早来自于文本印刷行业。在这个行业中文本的大小使用一种叫做点points)的概念作为单位来衡量其中 1 pt 1 / 72 inch 也就是说一个点是七十二分之一英寸大小一英寸为72个点。 我们现在使用的字体中的大小就叫做point size就是从印刷行业继承下来的。例如一个12-point大小的字体它的高度就是 12 / 72 1 / 6 英寸。 但当回到屏幕显示的时候就出现了问题。我们知道屏幕是以像素为单位的但在不同的屏幕中一个像素对应的实际物理宽度是不一样的这取决于屏幕真实的物理尺寸和屏幕的分辨率。 所以定义了一个新的单位来表示字体的大小新单位就是逻辑单元logical units。一个72 point大小的字体被定义为一个逻辑单元高。然后再将逻辑单元转化为像素。在Windows的发展历史中默认定义一个逻辑单元的大小为96像素。也就是说此时一个 72 point大小的字体将被绘制为96个像素。一个12 point 大小的字体会被绘制成为 16 个像素。 此时DPI的概念就从打印中转移到了屏幕显示中虽然名字叫 dots per inch但已经是屏幕显示中的概念了。默认的DPI为96即每英寸96个像素。一个逻辑单元为72 point72 point在印刷中为一英寸。 而操作系统中设置缩放率其本质就是在修改DPI的值。如果用户将DPI修改为了144那么72 point 大小的字体就会显示为144个像素高。标准DPI被设置为100%96 DPI125%120 DPI150144 DPI此外还有其他的设置。 这样我们就明白了为什么缩放率改变时文本的大小会变。这是因为字体的point size没有变化它的逻辑单元也不会变化但一个逻辑单元对应的像素发生了变化最后显示的像素高度就发生了变化。
5.Qt对高DPI的支持
本节内容是对Qt文档《High DPI Displays》的概述。
有两种方式可以对UI界面进行缩放 Qt不做任何事情由windows系统负责缩放 windows系统不做任何事情由Qt负责进行缩放 第一种方法是通过设置相关的环境变量实现的此时windows会按照缩放图片的方式缩放整个界面因为无论是文字还是UI都会同时放大缩小。好处是程序是可用的坏处是界面必然会模糊。 第二种方法则由Qt来负责缩放其思路是为了支持高DPI, Qt会自动缩放字体并提供一个DPI值应用程序代码可以使用它来缩放其余的UI。 第二种情况下所需的内容已在第一节中说明。
6.Pixmap中的devicePixelRatio
dpr的概念最初是来自于屏幕引用网上一段话解释 我们的主人公是乔帮主和比尔盖茨。此时乔帮主面前有一台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个物理像素点为其工作了而pixmap的dpr概念与之类似表示的是pixmap的size和想要绘制的设备无关像素之间的比例。例如一个200x200大小的pixmap如果它的dpr为2那么表示它将会被绘制到100x100的设备无关像素矩形内。我们引用QPainter文档中的《Drawing High Resolution Versions of Pixmaps and Images》一节所谓pixmap的高分辨率版本指的是device pixel ratio的值大于1的pixmap。当pixmap的dpr和底层的QPinterDevice的ptr一致时pixmap无需转化就可以直接绘制到相关设备上。例如一张64x64大小的图片dpr为2当他绘制在一个高DPI而且dpr也正好为2的屏幕上时最后实际绘制出来的时一个32x32像素大小的内容。当Qt中的代码根据pixmap的size来计算布局的尺寸时会使用图片的dpr得到真实有效的尺寸。这导致pixmap会按照给分辨率版本的形式显示32x32,但由于将图片提前进行了缩放显示后的图片不会变得模糊而不是显示为一个大的图片64x64。简言之如果想要最终显示为32x32像素大小那么在dpi为1时需要提供32x32的图片dpi为2时提供32x32的两倍大小的图片图片的dpr需要设置为2这样图片会先缩小2倍在放大2倍显示图片不会变得模糊依次类推。