QT解决因屏幕分辨率和缩放产生的界面异常

显示器分辨率和缩放比例

在某些情况下,由于屏幕分辨率和缩放比例不是100%,导致一些界面或字体的显示出现异常。此时需要获取到分辨率和缩放比例等相关参数,加以矫正,使界面在不同分辨率和缩放比例下都显示正常。
以Windows11为例,右键开始图标选择【系统】-【屏幕】,进入如下界面。
QT解决因屏幕分辨率和缩放产生的界面异常_第1张图片
找到【缩放和布局】
QT解决因屏幕分辨率和缩放产生的界面异常_第2张图片
此电脑的最佳缩放和显示器分辨率分别为200%,2560*1440;在此设置下可以达到最佳显示效果,但问题随之而来。

界面异常

正常情况,即100%缩放比例的情况下,一个图像显示窗口及字体如下,
QT解决因屏幕分辨率和缩放产生的界面异常_第3张图片
现在将显示器分辨率和缩放比例调整到2560*1440和200%,同一个界面和字体如下,
QT解决因屏幕分辨率和缩放产生的界面异常_第4张图片
可以看到,图像显示窗口和字体都随之改变,字体变小,图像显示区则直接缩小了1倍,这些结果都能和显示器缩放比例对应上,我们现在知道,显示器缩放比例调整为原来的2倍,则界面显示区随之变为原来的0.5倍。
接下来就是如何通过QT获取到相关参数进而对相应窗口进行尺寸调整。

QT(6.2版本)获取主屏幕分辨率和缩放比例

细心的人可能注意到,第一张图上显示的是两个显示器,其中1为主显示器。直接上QT帮助文档。在帮助文档里找到QScreen Class。
QT解决因屏幕分辨率和缩放产生的界面异常_第5张图片
找到其中几个接口:

 qreal devicePixelRatio() const
 qreal logicalDotsPerInch() const
 qreal logicalDotsPerInchX() const
 qreal logicalDotsPerInchY() const

其解释说说明如下,简单解释下:
QT解决因屏幕分辨率和缩放产生的界面异常_第6张图片
此属性保存物理像素和设备无关像素之间的屏幕比率。主要看这句就行,

Common values are 1.0 on normal displays and 2.0 on "retina" displays. Higher values are also possible

正常情况下值为1,解释下"retina" displays。

视网膜成像显示技术,一种超高分辨率显示技术。有兴趣可以百度一下
Retina Display

用法我们后面说。

QT解决因屏幕分辨率和缩放产生的界面异常_第7张图片
逻辑分辨率,和物理分辨率区分,物理分辨率我们用不到。所谓逻辑分辨率就是显示器每一英寸上的逻辑点数,就是我们常说的DPI。通常情况下XY方向值一样,平均值自然也一样。可根据实际情况选择使用。

该类通过静态接口函数获取

QScreen *screen = qApp->primaryScreen();

代码测试

下面进行无聊的测试环节。

    QScreen *screen = qApp->primaryScreen();
    qreal dpiVal = screen->logicalDotsPerInch();
    qreal ratioVal = screen->devicePixelRatio();
    qDebug() << dpiVal << ratioVal;

改个缩放值,运行一遍代码。
QT解决因屏幕分辨率和缩放产生的界面异常_第8张图片
输出值如下

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);
	}

就是在原有数据的基础上乘以这个缩放因子。
结果就不一一展示了,在不同缩放比例下已经一样了。
QT解决因屏幕分辨率和缩放产生的界面异常_第9张图片

需要说明下:这个常量DPI96在常见的显示器都是这个值,没有测试过所有显示器

多显示器

前面的方法是获取主显示器的参数值,多显示器情况下,也提供了接口

QList<QScreen *> QGuiApplication::screens()

这里就不赘述了

拓展

相信很多人都见过,一些应用程序在屏幕分辨率或缩放参数改变后或弹窗提示,以企业微信为例
QT解决因屏幕分辨率和缩放产生的界面异常_第10张图片
这个也很简单,QScreen类有很多信号
QT解决因屏幕分辨率和缩放产生的界面异常_第11张图片
只要绑定个槽函数,就能随时获取屏幕的参数变化,执行后续的操作,在线修改或者像企业微信那样做个提醒什么的,用法就很随意了。

    QScreen *screen = qApp->primaryScreen();
    connect(screen, &QScreen::logicalDotsPerInchChanged, [](double v){
        qDebug() << "new dpi " << v;
    });

你可能感兴趣的:(qt,ui)