文章

Qt传统窗口调整技术

Qt 传统窗口调整技术通过重写resizeEvent响应窗口大小变化,结合手动设置控件位置和尺寸,实现自定义布局和动态调整。

Qt传统窗口调整技术

Qt 传统窗口调整技术

QWidget 中与控件/窗口大小相关

大小设置相关函数

函数名参数作用是否允许用户调整大小
setFixedSize(int w, int h) / setFixedSize(const QSize &)宽度、高度设置固定大小❌ 不允许
resize(int w, int h) / resize(const QSize &)宽度、高度设置当前大小✅ 允许
setMinimumSize(int w, int h) / setMinimumSize(const QSize &)最小宽度、高度设置最小尺寸限制✅ 允许
setMaximumSize(int w, int h) / setMaximumSize(const QSize &)最大宽度、高度设置最大尺寸限制✅ 允许
setGeometry(int x, int y, int w, int h)坐标和宽高设置位置和大小✅ 允许
adjustSize()根据内容自动调整控件大小(调用 resize(sizeHint())✅ 允许

大小获取函数

函数名返回值类型作用
size()QSize获取当前控件大小
width() / height()int获取当前宽度或高度
minimumSize() / maximumSize()QSize获取最小/最大尺寸
geometry()QRect获取控件的矩形区域(位置+尺寸)

推荐尺寸(用于布局管理器)

函数名返回值类型作用备注
sizeHint()QSize返回推荐的大小可重写
minimumSizeHint()QSize返回推荐的最小大小默认为 (0,0),可重写

手动计算调整控件分布

widget.ui

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>472</width>
    <height>473</height>
   </rect>
  </property>
  <property name="minimumSize">
   <size>
    <width>0</width>
    <height>0</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QSlider" name="horizontalSlider">
   <property name="geometry">
    <rect>
     <x>160</x>
     <y>420</y>
     <width>231</width>
     <height>21</height>
    </rect>
   </property>
   <property name="orientation">
    <enum>Qt::Orientation::Horizontal</enum>
   </property>
  </widget>
  <widget class="QLabel" name="labelShow">
   <property name="geometry">
    <rect>
     <x>40</x>
     <y>10</y>
     <width>400</width>
     <height>300</height>
    </rect>
   </property>
   <property name="text">
    <string/>
   </property>
  </widget>
  <widget class="QPushButton" name="btnOpenPic">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>380</y>
     <width>75</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>打开图片</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btnOpenMov">
   <property name="geometry">
    <rect>
     <x>80</x>
     <y>380</y>
     <width>102</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>打开动态图</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btnStart">
   <property name="geometry">
    <rect>
     <x>200</x>
     <y>380</y>
     <width>91</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>播放</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btnStop">
   <property name="geometry">
    <rect>
     <x>330</x>
     <y>380</y>
     <width>91</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>停止</string>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

widget.h

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#ifndef WIDGET_H
#define WIDGET_H

#include <QImageReader> // 用于读取图像(错误类型也在此)
#include <QMovie>       // 用于播放动态图(如 GIF)
#include <QPixmap>      // 用于显示静态图像
#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget {
    Q_OBJECT

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

public slots:
    // 动图播放错误的槽函数,连接 QMovie::error 信号
    void recvPlayError(QImageReader::ImageReaderError error);

    // 帧变化的槽函数,用于更新进度条,连接 QMovie::frameChanged 信号
    void recvFrameNumber(int frameNumber);

private slots:
    // UI 按钮点击的槽函数(自动连接)
    void on_btnOpenPic_clicked(); // 打开静态图按钮
    void on_btnOpenMov_clicked(); // 打开动态图按钮
    void on_btnStart_clicked();   // 播放按钮
    void on_btnStop_clicked();    // 停止按钮

private:
    Ui::Widget* ui; // 指向 UI 界面类的指针,自动生成并管理所有控件

    // 用于显示静态图的指针(建议用智能指针管理)
    QPixmap* pixmap = nullptr;

    // 用于播放动态图的指针(如 gif/mng)
    QMovie* movie = nullptr;

    // 标志位:当前是否为动态图(true 表示是 QMovie)
    bool isMovie = false;

    // 标志位:动态图是否正在播放
    bool isPlaying = false;

    // 清除上一个图像或动画的辅助函数,释放资源并重置状态
    void clearOldShow();

    // QWidget interface
protected:
    void resizeEvent(QResizeEvent* event) override;
};

#endif // WIDGET_H
  • virtual void resizeEvent(QResizeEvent* event);QWidget 中的一个虚函数,用于处理 窗口或控件大小变化时的事件

  • 该事件对象提供了控件新旧尺寸的信息:

函数作用
event->size()返回新的大小 (QSize)
event->oldSize()返回旧的大小 (QSize)
  • 注意事项

  • 重写时不要忘记调用 QWidget::resizeEvent(event);,除非你完全取代默认行为

  • 如果控件用布局管理器(如 QVBoxLayoutQGridLayout),一般不需要手动处理大小变化。

  • C++11 开始,加入 override 有个好处:如果写错函数签名、参数、拼写等,没有 override 就不会报错,导致函数不会被调用。

widget.cpp

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include "widget.h"
#include "./ui_widget.h"
#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>
#include <QResizeEvent>
#include <QScrollArea>

// 构造函数:初始化 UI 并用 QScrollArea 包装 label 实现滚动支持
Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);

    // 获取 labelShow 的原始几何尺寸
    // 表示该控件相对于其父控件的几何信息(位置 + 大小)
    QRect rcLabel = ui->labelShow->geometry();

    // 创建一个滚动区域并将 labelShow 设置为其子控件
    QScrollArea* scrollArea = new QScrollArea(this);
    // 把 labelShow 这个 QLabel 设置为 scrollArea(滚动区域)的子控件。
    // scrollArea 会自动显示 labelShow 的内容;
    // 如果 labelShow 太大(超出 scrollArea 大小),scrollArea 会提供滚动条;
    // scrollArea 会接管 labelShow 的父对象和显示逻辑。
    scrollArea->setWidget(ui->labelShow);
    // 将 scrollArea 的大小和位置设置为 labelShow 原本在窗口中的位置和大小
    scrollArea->setGeometry(rcLabel);

    // 输出当前支持的图片与动画格式
    qDebug() << QImageReader::supportedImageFormats();
    qDebug() << QMovie::supportedFormats();

    // 设置主界面窗体最小尺寸
    this->setMinimumSize(350, 350);
}

// 析构函数:释放资源
Widget::~Widget() {
    clearOldShow(); // 清除旧显示内容(手动释放 pixmap 或 movie)
    delete ui;
}

// 清除旧的图像/动画内容,释放内存
void Widget::clearOldShow() {
    ui->labelShow->clear(); // 清空显示

    // 释放静态图资源
    if (pixmap != nullptr) {
        delete pixmap;
        pixmap = nullptr;
    }

    // 释放动态图资源
    if (movie != nullptr) {
        if (isPlaying) movie->stop(); // 正在播放先停止
        delete movie;
        movie = nullptr;
    }

    isMovie = false;
    isPlaying = false;
}

// 点击“打开图片”按钮后的响应槽函数
void Widget::on_btnOpenPic_clicked() {
    QString fileName;

    // 弹出文件选择对话框
    fileName = QFileDialog::getOpenFileName(this, tr("打开静态图"), "", "Pictures (*.bmp *.jpg *.jpeg *.png *.xpm);;All files(*)");
    if (fileName.isEmpty()) return;

    clearOldShow(); // 释放上一个资源
    qDebug() << fileName;

    pixmap = new QPixmap();
    if (pixmap->load(fileName)) {
        ui->labelShow->setPixmap(*pixmap);          // 设置图像
        ui->labelShow->setGeometry(pixmap->rect()); // 自动调整 label 大小
        isMovie = false;
        isPlaying = false;
    } else {
        delete pixmap;
        pixmap = nullptr;
        QMessageBox::critical(this, tr("打开失败"), tr("打开图片失败,文件名为:\r\n%1").arg(fileName));
    }
}

// 点击“打开动画”按钮后的响应槽函数
void Widget::on_btnOpenMov_clicked() {
    QString fileName;

    // 弹出文件选择对话框
    fileName = QFileDialog::getOpenFileName(this, tr("打开动态图"), "", "Movies (*.gif *.mng);;All files(*)");
    if (fileName.isEmpty()) return;

    clearOldShow(); // 清除旧资源
    qDebug() << fileName;

    movie = new QMovie(fileName);
    if (!movie->isValid()) {
        QMessageBox::critical(this, tr("动态图格式不可用"), tr("动态图格式不支持或读取出错,文件名为:\r\n%1").arg(fileName));
        delete movie;
        movie = nullptr;
        return;
    }

    // 获取总帧数(有些 gif 不支持,返回 -1)
    int count = movie->frameCount();
    qDebug() << tr("总帧数:%1").arg(count);

    // 设置滑动条最大值(回退默认值 100 以支持未知帧数)
    ui->horizontalSlider->setMaximum(count > 0 ? count : 100);

    // 设置动画显示到 label 中
    ui->labelShow->setMovie(movie);
    isMovie = true;
    isPlaying = false;

    // 使用新信号槽语法连接错误处理与帧更新
    connect(movie, &QMovie::error, this, &Widget::recvPlayError);
    connect(movie, &QMovie::frameChanged, this, &Widget::recvFrameNumber);

    // 跳转到第一帧并设置 label 大小
    if (movie->jumpToFrame(0)) {
        ui->labelShow->setGeometry(movie->frameRect());
    }
}

// “播放”按钮点击槽函数
void Widget::on_btnStart_clicked() {
    if (!isMovie || isPlaying) return; // 非动画或已经在播放
    isPlaying = true;
    movie->start();
    qDebug() << tr("循环计数:%1").arg(movie->loopCount());
}

// “暂停”按钮点击槽函数
void Widget::on_btnStop_clicked() {
    if (!isMovie || !isPlaying) return;
    isPlaying = false;
    movie->stop();
}

// 动画播放出错时的处理槽函数
void Widget::recvPlayError(QImageReader::ImageReaderError error) {
    qDebug() << tr("读取动态图错误的代码:%1").arg(error);
    QMessageBox::critical(this, tr("播放出错"), tr("播放动态图出错,文件名为:\r\n%1").arg(movie->fileName()));
    isPlaying = false;
}

// 每一帧更新时,设置滑动条位置
void Widget::recvFrameNumber(int frameNumber) {
    ui->horizontalSlider->setValue(frameNumber);
}

// 重写
void Widget::resizeEvent(QResizeEvent* event) {
    int W = event->size().width();
    int H = event->size().height();

    // 先计算第二行四个按钮的左上角坐标,按钮尺寸固定为 75*23
    // 第一个按钮
    int x1 = 10;                    // 左边距 10
    int y1 = H - 10 - 21 - 10 - 23; // 10 都是间隔,21 是水平滑动条高度,23 是按钮高度
    // 第四个按钮
    int x4 = W - 10 - 75; // 10 是右边距,75 是按钮宽度
    int y4 = y1;          // 与第一个按钮同一水平线
    // 计算四个按钮的三个间隙总大小
    int nTriGap = W - 10 - 10 - 75 * 4;
    // 计算单个间隙
    int nGap = nTriGap / 3;
    // 计算第二个按钮坐标
    int x2 = x1 + 75 + nGap;
    int y2 = y1;
    // 计算第三个按钮左边
    int x3 = x4 - 75 - nGap;
    int y3 = y1;

    // 设置四个按钮的矩形
    ui->btnOpenPic->setGeometry(x1, y1, 75, 23);
    ui->btnOpenMov->setGeometry(x2, y2, 75, 23);
    ui->btnStart->setGeometry(x3, y3, 75, 23);
    ui->btnStop->setGeometry(x4, y4, 75, 23);

    // 计算第三行水平滑动条的坐标和尺寸
    int xSlider = x2;
    int ySlider = H - 10 - 21;
    int wSlider = W - x2 - 10;
    int hSlider = 21;
    // 设置水平滑动条的矩形
    ui->horizontalSlider->setGeometry(xSlider, ySlider, wSlider, hSlider);

    // 计算包裹标签的滚动区域占用的矩形
    int xLabel = 10;
    int yLabel = 10;
    int wLabel = W - 10 - 10;
    int hLabel = H - 10 - 21 - 10 - 23 - 10 - 10;
    // 设置包裹标签的滚动区域矩形
    QScrollArea* pSA = this->findChild<QScrollArea*>(); // 查找子对象
    // 如果 pSA 不为 nullptr 才能设置矩形
    if (pSA != nullptr) pSA->setGeometry(xLabel, yLabel, wLabel, hLabel);
}

计算文本显示宽度

QWidget::adjustSize()

QWidget::adjustSize() 会根据控件内容(比如子控件的大小、布局、字体等)自动调整当前控件的大小,以“刚好能包住内容”为目标。

1
2
3
QLabel* label = new QLabel(this);
label->setText("动态内容");
label->adjustSize();  // 让 QLabel 自动变大以显示完整内容

adjustSize() 实际上是调用 sizeHint() 获取推荐尺寸,然后调用 resize(sizeHint())

1
2
3
void QWidget::adjustSize() {
    resize(sizeHint());
}

如果你重写了 sizeHint(),它就会使用你提供的尺寸。

QFontMetrics

QFontMetrics 是 Qt 中用于 测量字体相关尺寸信息 的类,主要功能是根据某个字体 QFont计算文本的大小、行高、对齐、间距等信息。它对布局、自定义绘制控件、精确控制文本位置等非常重要。

常用构造方式
1
2
QFont font("Microsoft YaHei", 12);
QFontMetrics metrics(font);

也可以在 widget 的 paintEvent 中直接使用当前字体:

1
QFontMetrics metrics(this->font());
常用函数速查表
函数名返回类型说明
width(const QString &text)(Qt5)horizontalAdvance(const QString &text)(Qt6)int获取字符串的水平宽度(像素)
height()int获取总高度(行高)
ascent()int获取字体基线以上的高度
descent()int获取字体基线以下的高度
leading()int获取行间距(行与行之间的额外空间)
boundingRect(const QString &text)QRect返回包围文字的矩形区域
elidedText(text, mode, width)QString超出宽度时加省略号(…)的文本

示例:计算字符串宽度并设置 QLabel 宽度

1
2
3
4
QLabel* label = new QLabel("Hello Qt");
QFontMetrics metrics(label->font());
int width = metrics.horizontalAdvance("Hello Qt");
label->setFixedWidth(width);  // 宽度正好包住文字
QFontMetrics vs QFontMetricsF
  • QFontMetrics 返回的是整数,精度较低,常用于普通控件;

  • QFontMetricsF 返回的是浮点数,适用于高精度绘制(比如自定义 OpenGL 渲染控件)。

QFontMetrics::size()

1
QSize QFontMetrics::size(int flags, const QString &text) const;

返回给定 text 在指定绘图标志(flags)下所需的尺寸(QSize),适用于多行文本和复杂格式的测量

这比 horizontalAdvance() 更通用(后者只测一行宽度),支持多行、对齐方式等更多排版控制

参数含义说明
flagsQt::TextFlag 类型的标志位,例如对齐方式、是否换行等
text要计算的文本内容

常用 flags 值有:

  • Qt::TextSingleLine:单行显示(默认不换行)
  • Qt::TextWordWrap:自动换行
  • Qt::AlignLeft, Qt::AlignCenter, Qt::AlignRight:对齐方式
示例代码
1
2
3
4
5
6
7
QFont font("Microsoft YaHei", 12);
QFontMetrics metrics(font);

QString text = "This is a\nmulti-line text.";
QSize size = metrics.size(Qt::TextWordWrap, text);

qDebug() << "宽度:" << size.width() << "高度:" << size.height();

示例

widget.ui
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>391</width>
    <height>267</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QLabel" name="label_1">
   <property name="geometry">
    <rect>
     <x>30</x>
     <y>30</y>
     <width>53</width>
     <height>24</height>
    </rect>
   </property>
   <property name="text">
    <string>按钮文本</string>
   </property>
  </widget>
  <widget class="QLabel" name="label_2">
   <property name="geometry">
    <rect>
     <x>20</x>
     <y>80</y>
     <width>53</width>
     <height>24</height>
    </rect>
   </property>
   <property name="text">
    <string>动态按钮</string>
   </property>
  </widget>
  <widget class="QLabel" name="label_3">
   <property name="geometry">
    <rect>
     <x>20</x>
     <y>130</y>
     <width>53</width>
     <height>24</height>
    </rect>
   </property>
   <property name="text">
    <string>固定按钮</string>
   </property>
  </widget>
  <widget class="QLineEdit" name="lineEdit">
   <property name="geometry">
    <rect>
     <x>100</x>
     <y>30</y>
     <width>113</width>
     <height>24</height>
    </rect>
   </property>
  </widget>
  <widget class="QPushButton" name="btnDynamic">
   <property name="geometry">
    <rect>
     <x>110</x>
     <y>80</y>
     <width>75</width>
     <height>24</height>
    </rect>
   </property>
   <property name="text">
    <string>动态</string>
   </property>
  </widget>
  <widget class="QPushButton" name="btnFixed">
   <property name="geometry">
    <rect>
     <x>120</x>
     <y>130</y>
     <width>75</width>
     <height>24</height>
    </rect>
   </property>
   <property name="text">
    <string>固定</string>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>
widget.h
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
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget {
    Q_OBJECT

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

  private slots:
    void on_lineEdit_textEdited(const QString& arg1);

  private:
    Ui::Widget* ui;

    // QWidget interface
  protected:
    void resizeEvent(QResizeEvent* event) override;
};
#endif // WIDGET_H
widget.cpp
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "widget.h"
#include "./ui_widget.h"
#include <QResizeEvent>

Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);
    // 设置窗口的最小尺寸,确保内容不会被挤压得太小
    // 计算最小宽度:10(左边距) + 54(标签宽度) + 10(间隙) + 75(第三行按钮宽度) + 10(右边距)
    // 计算最小高度:24(单行控件高度) * 3(行数) + 10(上下间隙) * 4(行间及边距数量)
    this->setMinimumSize(10 + 54 + 10 + 75 + 10, 24 * 3 + 10 * 4);
}

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

void Widget::on_lineEdit_textEdited(const QString& arg1) {
    QFontMetrics fm = ui->btnDynamic->fontMetrics();

    // 计算文本的宽度(像素)
    int nTextWidth = fm.horizontalAdvance(arg1);
    // 获取动态按钮当前大小
    QSize szButtonDynamic = ui->btnDynamic->size();
    // 按文本宽度调整按钮宽度,增加10像素边距留白
    szButtonDynamic.setWidth(nTextWidth + 10);
    ui->btnDynamic->resize(szButtonDynamic);
    // 设置按钮文本和提示内容
    ui->btnDynamic->setText(arg1);
    ui->btnDynamic->setToolTip(arg1);

    // 固定按钮文本处理:如果文本宽度小于等于65,直接显示
    if (nTextWidth <= 65) {
        ui->btnFixed->setText(arg1);
    } else {
        // 否则截断文本并加省略号,确保按钮宽度不超过65像素
        QString strPart;
        QString strDot = "...";
        int nStrLen = arg1.length();
        int nNewTextWidth = 0;
        for (int i = 0; i < nStrLen; i++) {
            strPart += arg1[i];
            nNewTextWidth = fm.horizontalAdvance(strPart + strDot);
            if (nNewTextWidth >= 65) break;
        }
        ui->btnFixed->setText(strPart + strDot);
    }
    ui->btnFixed->setToolTip(arg1);
}

void Widget::resizeEvent(QResizeEvent* event) {
    // 获取窗口当前宽度和高度
    int W = event->size().width();
    int H = event->size().height();

    // 第一行控件布局
    // 标签1 固定大小54x24,垂直居中在窗口的1/4高度处
    int xLabel1 = 10;         // 左边距10像素
    int yLabel1 = H / 4 - 12; // 标签垂直居中,24高度减半为12
    ui->label_1->move(xLabel1, yLabel1);

    // 单行编辑控件布局
    int xLineEdit = xLabel1 + 54 + 10; // 紧邻标签右侧,间隙10像素
    int yLineEdit = yLabel1;
    int wLineEdit = W - xLineEdit - 10; // 编辑框宽度占剩余宽度,右边距10像素
    int hLineEdit = 24;                 // 高度固定24像素
    ui->lineEdit->setGeometry(xLineEdit, yLineEdit, wLineEdit, hLineEdit);

    // 第二行控件布局
    // 标签2 固定大小54x24,垂直居中在窗口的2/4高度处
    int xLabel2 = 10;
    int yLabel2 = 2 * H / 4 - 12;
    ui->label_2->move(xLabel2, yLabel2);
    // 动态按钮紧邻标签右侧,大小由槽函数动态调整
    int xButtonDynamic = xLabel2 + 54 + 10;
    int yButtonDynamic = yLabel2;
    ui->btnDynamic->move(xButtonDynamic, yButtonDynamic);

    // 第三行控件布局
    // 标签3 固定大小54x24,垂直居中在窗口的3/4高度处
    int xLabel3 = 10;
    int yLabel3 = 3 * H / 4 - 12;
    ui->label_3->move(xLabel3, yLabel3);
    // 固定按钮紧邻标签右侧,大小固定
    int xButtonFixed = xLabel3 + 54 + 10;
    int yButtonFixed = yLabel3;
    ui->btnFixed->move(xButtonFixed, yButtonFixed);
}
本文由作者按照 CC BY 4.0 进行授权