问题:
我们都知道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);
}