在某些情况下,由于屏幕分辨率和缩放比例不是100%,导致一些界面或字体的显示出现异常。此时需要获取到分辨率和缩放比例等相关参数,加以矫正,使界面在不同分辨率和缩放比例下都显示正常。
以Windows11为例,右键开始图标选择【系统】-【屏幕】,进入如下界面。
找到【缩放和布局】
此电脑的最佳缩放和显示器分辨率分别为200%,2560*1440;在此设置下可以达到最佳显示效果,但问题随之而来。
正常情况,即100%缩放比例的情况下,一个图像显示窗口及字体如下,
现在将显示器分辨率和缩放比例调整到2560*1440和200%,同一个界面和字体如下,
可以看到,图像显示窗口和字体都随之改变,字体变小,图像显示区则直接缩小了1倍,这些结果都能和显示器缩放比例对应上,我们现在知道,显示器缩放比例调整为原来的2倍,则界面显示区随之变为原来的0.5倍。
接下来就是如何通过QT获取到相关参数进而对相应窗口进行尺寸调整。
细心的人可能注意到,第一张图上显示的是两个显示器,其中1为主显示器。直接上QT帮助文档。在帮助文档里找到QScreen Class。
找到其中几个接口:
qreal devicePixelRatio() const
qreal logicalDotsPerInch() const
qreal logicalDotsPerInchX() const
qreal logicalDotsPerInchY() const
其解释说说明如下,简单解释下:
此属性保存物理像素和设备无关像素之间的屏幕比率。主要看这句就行,
Common values are 1.0 on normal displays and 2.0 on "retina" displays. Higher values are also possible
正常情况下值为1,解释下"retina" displays。
视网膜成像显示技术,一种超高分辨率显示技术。有兴趣可以百度一下
Retina Display
用法我们后面说。
逻辑分辨率,和物理分辨率区分,物理分辨率我们用不到。所谓逻辑分辨率就是显示器每一英寸上的逻辑点数,就是我们常说的DPI。通常情况下XY方向值一样,平均值自然也一样。可根据实际情况选择使用。
该类通过静态接口函数获取
QScreen *screen = qApp->primaryScreen();
下面进行无聊的测试环节。
QScreen *screen = qApp->primaryScreen();
qreal dpiVal = screen->logicalDotsPerInch();
qreal ratioVal = screen->devicePixelRatio();
qDebug() << dpiVal << ratioVal;
window 缩放参数 | 100% | 125% | 150% | 175% | 200% | 225% |
---|---|---|---|---|---|---|
logicalDotsPerInch | 96 | 120 | 72 | 84 | 96 | 108 |
devicePixelRatio | 1 | 1 | 2 | 2 | 2 | 2 |
规律很明显,稍微有点数学常识的人应该都可以总结出来,他们之间存在着线性关系,即
window缩放参数 / 100% = logicalDotsPerInch * devicePixelRatio / 96
找到规律,就好办了,在使用的地方定义一个函数。
double SomeClass::GetScreenFactor()
{
//获取屏幕缩放倍数
QScreen *screen = qApp->primaryScreen();
const int baseValue = 96;//100%时为96
qreal dpiVal = screen->logicalDotsPerInch();
qreal ratioVal = screen->devicePixelRatio();
qDebug() << dpiVal << ratioVal;
return dpiVal * ratioVal / baseValue;
}
具体哪里会用到就要根据自己的实际情况了,最常见的两个地方是
以一段项目代码为例
//界面构造或者初始化时
...
auto factor = d->GetScreenFactor();
d->pHalconView = std::make_unique<HalconView>();
double iWindowWidth = ui->widget_view->width() * factor;
double iWindowHeight = ui->widget_view->height() * factor;
QPoint qPos = ui->widget_view->mapFromParent(QPoint(0, 0));
d->pHalconView->InitWindow(qPos.x(), qPos.y(), iWindowWidth, iWindowHeight, (void *)(ui->widget_view->winId()), strWindowName);
...
//重写resizeEvent
void SomeClass::resizeEvent(QResizeEvent *event)
{
...
auto factor = d->GetScreenFactor();
d->pHalconView->ChangeWindowSize(0, 0, ui->widget_view->width() * factor, ui->widget_view->height() * factor);
...
QWidget::resizeEvent(event);
}
就是在原有数据的基础上乘以这个缩放因子。
结果就不一一展示了,在不同缩放比例下已经一样了。
需要说明下:这个常量DPI96在常见的显示器都是这个值,没有测试过所有显示器
前面的方法是获取主显示器的参数值,多显示器情况下,也提供了接口
QList<QScreen *> QGuiApplication::screens()
这里就不赘述了
相信很多人都见过,一些应用程序在屏幕分辨率或缩放参数改变后或弹窗提示,以企业微信为例
这个也很简单,QScreen类有很多信号
只要绑定个槽函数,就能随时获取屏幕的参数变化,执行后续的操作,在线修改或者像企业微信那样做个提醒什么的,用法就很随意了。
QScreen *screen = qApp->primaryScreen();
connect(screen, &QScreen::logicalDotsPerInchChanged, [](double v){
qDebug() << "new dpi " << v;
});