Qt适配Windows缩放

问题:

  我们都知道windows系统有缩放功能,能够按比例缩小或者放大控件和文字。
在这里插入图片描述
但是Qt默认的对其支持的效果并不是特别好。比如:
125%:
在这里插入图片描述
175%:
在这里插入图片描述
  从上面两张图可以看出字体相应的放大了,但是控件大小并没有放大,导致字体显示不全。

解决方案:

一、固定大小不变。

  无论缩放比例是多少,控件大小和字体大小都不变。字体我们使用 setPixelSize(int pixelSize) 方法。

QFont font;
font.setPixelSize(14);
ui->pushButton->setFont(font);
ui->pushButton_2->setFont(font);
ui->label->setFont(font);

效果:
125%:
在这里插入图片描述
175%:
在这里插入图片描述
  这种方法虽然解决了字体显示不全的问题,但是没法缩放字体和控件大小,并不完美。下面看方法二。

二、计算缩放系统对控件大小进行缩放。

  有关windows的DPI缩放的可以先看下这里: https://docs.microsoft.com/en-us/previous-versions//dn953371(v=vs.85)
  由以上我们可以知道qt默认的是字体可以进行自由缩放,因为默认的是设置pointSize。point size 规定了实际中我们肉眼看到的字体的大小 他和pixel无关的,他和显示器无关不管在什么样上的显示器上规定大小是多少就是多少。pixel size 是所占的像素大小,即便进行缩放,他的大小也并没有改变,所占像素也并没有改变。
  我们首先了解一下DPI,DPI:Dot per inch,在显示器上也就是每英寸包含的像素。英尺的换算为 1 inch = 2.54 cm。windows上的逻辑DPI都是96。如果进行缩放的话那么相应的逻辑DPI会变为96*缩放系数。比如125%的话逻辑DPI就是120;我们无法直接获取125%,但是可以通过QScreen的
logicalDotsPerInch()方法来获取当前的逻辑DPI,再除以94来计算当前的缩放系数。
计算方法:

int scaleUI(int spec)
{
    double rate = 0;
    QList<QScreen*> screens = QApplication::screens();
    if (screens.size() > 0) {
        QScreen* screen = screens[0];
        double dpi = screen->logicalDotsPerInch();
        rate = dpi / 96.0;

        if (rate < 1.1) {
            rate = 1.0;
        } else if (rate < 1.4) {
            rate = 1.25;
        } else if (rate < 1.6) {
            rate = 1.5;
        } else if (rate < 1.8) {
            rate = 1.75;
        } else {
            rate = 2.0;
        }
    }
    return int(spec * rate);
}

使用方法:

 ui->pushButton->resize(scaleUI(93), scaleUI(28));
 ui->pushButton_2->resize(scaleUI(186), scaleUI(56));
 ui->label->resize(scaleUI(93), scaleUI((28)));

100%:
在这里插入图片描述
125%:
在这里插入图片描述
175%:
在这里插入图片描述
加入在切换缩放系数时自动缩放大小:
widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

public Q_SLOTS:
    void  onLogicalDotsPerInchChanged(qreal dpi);

private:
    void findChild(const QObject &o);
    int scaleUI(int spec);

private:
    Ui::Widget *ui;

    double m_preRate;
    double m_scaleFromPreRate;
};

#endif // WIDGET_H

widget.cpp

#include <QDebug>
#include <QScreen>
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    ui->pushButton->resize(scaleUI(93), scaleUI(28));
    ui->pushButton_2->resize(scaleUI(186), scaleUI(56));
    ui->label->resize(scaleUI(93), scaleUI((28)));

    QList<QScreen*> screens = QApplication::screens();
    if (screens.size() > 0) {
        QScreen* screen = screens[0];
        connect(screen, &QScreen::logicalDotsPerInchChanged, this, &Widget::onLogicalDotsPerInchChanged);
    }

}

Widget::~Widget()
{
    delete ui;
}

void Widget::onLogicalDotsPerInchChanged(qreal dpi)
{
    m_scaleFromPreRate = (double)dpi / 96 / m_preRate;
    m_preRate = (double)dpi / 96;
    findChild(*this);
}

void Widget::findChild(const QObject &o)
{
    for (int i=0; i<o.children().size(); ++i) {
        QWidget *pWidget = qobject_cast<QWidget *>(o.children().at(i));
        if (pWidget != nullptr) {
            qDebug() << pWidget->width() << pWidget->height();
            pWidget->resize(pWidget->width()*m_scaleFromPreRate, pWidget->height()*m_scaleFromPreRate);
            findChild(*(o.children().at(i)));
        }
    }
}

int Widget::scaleUI(int spec)
{
    double rate = 0;
    if (0 == (int)rate) {
        QList<QScreen*> screens = QApplication::screens();
        if (screens.size() > 0) {
            QScreen* screen = screens[0];
            double dpi = screen->logicalDotsPerInch();
            rate = dpi / 96.0;

            if (rate < 1.1) {
                rate = 1.0;
            } else if (rate < 1.4) {
                rate = 1.25;
            } else if (rate < 1.6) {
                rate = 1.5;
            } else if (rate < 1.8) {
                rate = 1.75;
            } else {
                rate = 2.0;
            }
        }
    }
    m_preRate = rate;
    return int(spec * rate);
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值