Qt5之前,Qt写出来的程序是完全不支持高DPI自适应的,无论DPI多少,都是按照死板的像素值绘制控件等。从Qt5开始,Qt开始支持了高DPI,但效果不算太好——默认只支持整数倍缩放,且如果强制使用小数倍缩放,会出现一些奇怪的问题,比如控件边界不清楚、失真等问题。

我尝试装过Qt5,但由于静态编译出了些问题,只得又退回Qt4.8。在各个论坛询问如何适应高DPI环境,没有任何一个回答是能满足我的要求的,或许Qt本身就有局限性。几天后,我心中出现了一个想法。按照系统DPI设置,重新调整控件的大小,不就行了吗?

说干就干,按照这个思路,写了一段代码,测试效果还不错,贴在这里,大家若有需要可以测试效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 注意:需要在文件的最上端引入QList( #include <QList> )
qreal factor = logicalDpiX() / (96.0 * 1.25); // 1.25更改为你用来设计UI的显示器的缩放系数
if (factor != 1.0)
{
resize(width()*factor, height()*factor);
QList<QWidget*> allControls = findChildren<QWidget*>();
QWidget *wid;
QString qss;
for (int i=0; i<allControls.size(); i++)
{
wid = allControls[i];
// 移动、缩放控件
wid->move(wid->x()*factor, wid->y()*factor);
wid->resize(wid->width()*factor, wid->height()*factor);
// 调整qss样式表中的像素值
qss = wid->styleSheet();
if (qss.length() > 0)
{
int p, s = 0;
QChar c;
QString snum;
// 寻找“数字+px”结构
while ((p = qss.indexOf("px", s, Qt::CaseInsensitive)) != -1)
{
snum.clear();
s = p + 2;
while ((c=qss[--p]).isDigit())
snum = c + snum;
p = (int)(snum.toInt()*factor); // 对数字进行调整
if (p > 0)
qss.replace(snum + "px", QString::number(p));
}
wid->setStyleSheet(qss);
}
}
QSize siz;
QList<QAbstractButton*> allBtns = findChildren<QAbstractButton*>();
for (int j=0; j<allBtns.size(); j++)
{
siz = allBtns[j]->iconSize();
siz *= factor;
allBtns[j]->setIconSize(siz);
}
}

得将第一行的1.25改成你用来设计UI的显示器的缩放系数。我用笔记本设计UI,缩放系数是125%,所以我写1.25。大部分台式机显示器都是100%。修改完后,把这段代码贴在主窗口的初始化函数中即可。

测试项目图片在下面。可以看出,在高DPI显示器中,程序自适应高DPI(左)和强制使用系统缩放(右)两种方式下,窗口、控件的大小基本相同,而且自适应的更加清晰。

参考: