〇、前言

在我写程序时遇到这样一个问题:

控件大小明明是 779x579,并且在 MainWindow 中实际显示大小也是 779x579

但是,当我使用控件的 size() 函数获取大小时却总是给出 100x30 的尺寸。

经过验证,确确实实是无法获取正确的控件尺寸信息,其他相关函数如下:

1
2
3
4
size()
width()
height()
geometry()

这非常的奇怪,也带来了一些麻烦。为了解决这个问题,查找了一些资料,最后解决了问题。

一、问题再现

首先,为了研究这个问题,我新建了一个名为 GetComponentSize 的项目。在这个项目中,只三个初始文件,具体项目结构如下:

1
2
3
4
5
GetComponentSize.pro/
├── mainwindow.h
├── mainwindow.cpp
├── main.cpp
└── mainwindow.ui

如果直接拖拽一个控件到 centralwidget 上并获取控件尺寸,则不会出现获取控件尺寸不正确的问题。

经过反复验证,该问题只出现在 Layouts 布局中。例如,我们可以这样弄一个简单的布局并添加一个 QWidget 控件:

图 1.1 控件及布局情况

为了便于观察到 QWidget 控件的实际情况,我们给其添加背景色样式:

1
background-color: rgb(255, 85, 127);

然后,我们构建项目并启动程序:

图 1.2 程序运行情况

很明显,问题出现了!明明控件本身在 Qt Designer 里显示的尺寸是 777x577,但是MainWindow 的构造函数中获取到的却是 100x30,而实际上显示的大小却是 781x581

主窗口尺寸为 800x600HLayoutVLayout 的 layoutSpacing 与 margin 均为 0,同时保持上右下左各个方向与主窗口保持 10px 的距离,所以才会得到实际显示大小为 781x581。至于这个多出来的 1,其与系统边框有关,这里不作讨论。

二、问题解决

先说问题是如何解决的!

2.1 重写 showEvent 函数

请直接参考下面的代码:

1
2
3
4
5
6
7
8
9
// ... ...
#include <QShowEvent>

// ... ...
class MainWindow : public QMainWindow {
// ... ...
void showEvent(QShowEvent* event) override;
// ... ...
};
1
2
3
4
5
6
7
8
9
// ... ...
void MainWindow::showEvent(QShowEvent *event) {
qDebug()<< "\n===== From showEvent =====\n"
<< "Widget Size is" << ui->Widget->size() << "\n"
<< "Other Info:\n"
<< "width\t" << ui->Widget->width() << "\n"
<< "height\t" << ui->Widget->height() << "\n"
<< "geometry\t" << ui->Widget->geometry() << "\n";
}

上述代码的运行的结果可以参考下图(最新补充:那个 300 是因为我修改了 Widget 的最小宽度):

图 2.1.1 程序运行情况

可见在 showEvent 里可以轻松获取正确的尺寸,所以只需要将原来的一些相关的逻辑代码转移到 showEvent 里重写即可。

2.2 重写 resizeEvent 函数

这个不知道为什么,网上有人说可以,但是我并测试没有成功。所以,这里我不展示这部分代码!

我的配置如下:

构建器:Qt 6.15 MSVC2019 64bit
操作系统:Windows 10 22H2

如果有清楚的朋友,还望不吝赐教🌹。

三、问题深究

经过不断深入研究,我最后大致弄明白了产生问题的原因(不确保完全正确)。

在 Qt 中的控件(后面将全部以前文的 QWidget 举例)设置大小的策略大致是这样的流程(自己推测的):

图 3.1 Qt 控件设置大小的流程

  • 布局管理器计算大小:当一个 QWidget 被添加到布局管理器中时,布局管理器会根据控件的大小策略和布局规则计算出控件的理想大小。
  • 考虑父控件的大小:如果 QWidget 是作为子控件添加到父控件中的,则父控件的大小也会影响到 QWidget 的大小(而 QLayout 之类的布局组件初始大小为 0x0)。QWidget 会根据父控件的大小和布局管理器的规则来确定自己的最终大小。
  • 设置最小尺寸:如果没有显式设置最小尺寸,QWidget 可能会使用默认的最小尺寸(通常为 100x30)。
  • 最终调整大小:最终,QWidget 会根据布局管理器和父控件的大小来调整自己的大小,以适应布局的要求和父控件的大小。

所以,可以肯定的是 MainWindow 的构造函数一定是最终调整大小之前,设置最小尺寸之后。

毕竟这只是我的推理,所以想了解的可以参考一下我的想法。

剩下的不能多说了(我也怕说错了😥),所以自己理解吧!大概就是这么个思路!