006-Qt 的布局

auther: abinng date: 2026-03-19 15:51 createDate:2026-03-19 15:51

常用布局

QHBoxLayout:水平布局 QVBoxLayout:垂直布局 QGridLayout:网格布局 QFormLayout:表单布局

代码实践

0. 说明一下

这里我们要写代码了,先清晰一下结构

我们在 QtCreator 中创建了 QWidget 程序后,会有四个主要文件:main.cpp, widget.h, widget.cpp, widget.ui

当我们用鼠标点的方式设计了 widget.ui 时,还会临时生成一个 ui_widget.h ,在 widget.cpp 中的构造函数内部有一个 ui->setupUiCtrl + 左键 的方式就可以定位到 ui_widget.h

首先 main.cpp 中:

1
2
3
4
5
6
7
8
9
10
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

w.show() 主要是为了让我们自定义的 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
#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:
void show1();
void myshow1();
Ui::Widget *ui;
};
#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
// widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QSizePolicy>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QGridLayout>
#include <QComboBox>
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>

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

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

void Widget::myshow1()
{
this->setGeometry(50, 100, 450, 400);
// 主布局
auto *main_layout = new QHBoxLayout(this);
// GroupBox
auto *grp = new QGroupBox(this);
// GroupBox 布局
auto *grp_layout = new QVBoxLayout(grp);
// 按钮名称
QList<QString> btn_names = {"画笔", "橡皮擦", "清空"};
// 大小策略定义
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
for(const auto &x : std::as_const(btn_names)) {
auto *btn = new QPushButton(x, grp);
btn->setSizePolicy(sizePolicy);
grp_layout->addWidget(btn);
}
// groupBox 中的比例
grp_layout->setStretch(0, 0);
grp_layout->setStretch(1, 2);
grp_layout->setStretch(2, 1);
// TextEdit
auto *edit = new QTextEdit(this);

// 加到主布局中
main_layout->addWidget(grp);
main_layout->addWidget(edit);
// 主布局比例
main_layout->setStretch(0, 1);
main_layout->setStretch(1, 2);
}

注意在构造函数中调用 myshow1() ,同时将 ui->setupUi(this) 注释,因为这个是调用 ui_widget.h 中的 setupUi 函数,是根据 Ui 设计器自动生成的代码

好,接下来开始写 UI

1. 水平、垂直布局

用代码做出如下效果:

从外往内看:

主布局是水平布局,左边是 GroupBox ,右边是 TextEdie ,左右比例是 1,2

GroupBox 中,三个按钮垂直布局,均为 Expanding 策略,从上到下比例是0,2,1

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
void Widget::myshow1()
{
this->setGeometry(50, 100, 450, 400);
// 主布局
auto *main_layout = new QHBoxLayout(this);
// GroupBox
auto *grp = new QGroupBox(this);
// GroupBox 布局
auto *grp_layout = new QVBoxLayout(grp);
// 按钮名称
QList<QString> btn_names = {"画笔", "橡皮擦", "清空"};
// 大小策略定义
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
for(const auto &x : std::as_const(btn_names)) {
auto *btn = new QPushButton(x, grp);
btn->setSizePolicy(sizePolicy);
grp_layout->addWidget(btn);
}
// groupBox 中的比例
grp_layout->setStretch(0, 0);
grp_layout->setStretch(1, 2);
grp_layout->setStretch(2, 1);
// TextEdit
auto *edit = new QTextEdit(this);

// 加到主布局中
main_layout->addWidget(grp);
main_layout->addWidget(edit);
// 主布局比例
main_layout->setStretch(0, 1);
main_layout->setStretch(1, 2);
}

2. 网格布局

用代码写出以下效果

主布局中一个 GroupBox ,从上到下是 Label, Widget(Label & ComboBox, 1:2), TextEdit, 两个按钮

第一行标题:Label,邮件发送客户端,居中,占1行两列

第二行一个 Widget,水平布局,占一行两列,左边一个 Label,右边一个 ComboBox,比例 1:2,ComboBox 中包含三个选项

第三行一个 TextEdit,占一行两列

第四行两个按钮 PushButton,均占用一行一列,位置分别是第四行第一列和第四行第二列

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
void Widget::myshow2()
{
// 窗口的左上角坐标,横长,纵宽
this->setGeometry(50, 100, 450, 400);
// 主 Widget 上只有一个组件,水平/垂直布局都行
auto *main_layout = new QHBoxLayout(this);
// 创建一个 GroupBox 用来放我们的表格,其实直接在 Widget 上放也行
auto *grp = new QGroupBox(this);
// GroupBox 的表格布局
auto *grp_layout = new QGridLayout(grp);
// 表格里面的组件
// 主标题
auto *main_label = new QLabel("邮件发送客户端", grp);
main_label->setAlignment(Qt::AlignCenter);
// lable 和下拉框
auto *send_widget = new QWidget(grp);
auto *send_widget_layout = new QHBoxLayout(send_widget);
auto *sendto_label = new QLabel("发送给:", send_widget);
auto *cmbbox = new QComboBox(send_widget);
cmbbox->addItem("abinng");
cmbbox->addItem("bbinng");
cmbbox->addItem("cbinng");
send_widget_layout->addWidget(sendto_label);
send_widget_layout->addWidget(cmbbox);
send_widget_layout->setStretch(0, 1);
send_widget_layout->setStretch(1, 2);
// 文本框
auto *edit = new QTextEdit(grp);
// 按钮
auto *btn1 = new QPushButton("清空", grp);
auto *btn2 = new QPushButton("发送", grp);
// grp_layout->addWidget(sendto_label, 0, 0, 1, 1);
// grp_layout->addWidget(cmbbox, 0, 1, 1, 1);
grp_layout->addWidget(main_label, 0, 0, 1, 2);
grp_layout->addWidget(send_widget, 1, 0, 1, 2);
grp_layout->addWidget(edit, 2, 0, 1, 2);
grp_layout->addWidget(btn1, 3, 0, 1, 1);
grp_layout->addWidget(btn2, 3, 1, 1, 1);

main_layout->addWidget(grp);
}

3. 表单布局,伙伴关系

用代码实现以下效果:

主布局中一个 GroupBox ,采用表单布局,从上到下依次是:标题 Label,两组输入组件 (Label & LineEdit),以及两个按钮 PushButton。

第一行标题:Label,登录客户端,居中,占用一行两列(跨两列)。

第二行用户名输入:左边一个 Label(包含快捷键 &n),右边一个 LineEdit,分别占用表单布局的左右两列,且 Label 设为 LineEdit 的伙伴(Buddy)。

第三行密码输入:左边一个 Label(包含快捷键 &p),右边一个 LineEdit,分别占用表单布局的左右两列,且 Label 设为 LineEdit 的伙伴(Buddy)。

第四行一个按钮:PushButton(注册),占用一行两列(跨两列)。

第五行一个按钮:PushButton(登录),占用一行两列(跨两列)。

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
void Widget::myshow3()
{
// 窗口的左上角坐标,横长,纵宽
this->setGeometry(50, 100, 450, 400);
// 主 Widget 上只有一个组件,水平/垂直布局都行
auto *main_layout = new QHBoxLayout(this);
// 创建一个 GroupBox 用来放我们的表单,其实直接在 Widget 上放也行
auto *grp = new QGroupBox(this);
// GroupBox 中的表单布局
auto *grp_layout = new QFormLayout(grp);
// 表单里面的组件
// 主标题
auto *main_label = new QLabel("登录客户端", grp);
main_label->setAlignment(Qt::AlignCenter); // 居中
// 用户名输入行
auto *username_label = new QLabel("用户名(&n)", grp);
auto *username_edit = new QLineEdit(grp);
username_label->setBuddy(username_edit); // 设置用户名行伙伴关系
// 密码输入行
auto *password_label = new QLabel("密码(&p)", grp);
auto *password_edit = new QLineEdit(grp);
password_label->setBuddy(password_edit); // 设置密码行伙伴关系
// 注册按钮
auto *signup_btn = new QPushButton("注册", grp);
// 登录按钮
auto *login_btn = new QPushButton("登录", grp);

// 加进 GroupBox 的布局
grp_layout->addRow(main_label);
grp_layout->addRow(username_label, username_edit);
grp_layout->addRow(password_label, password_edit);
grp_layout->addRow(signup_btn);
grp_layout->addRow(login_btn);

// 加进 主Widget 的布局
main_layout->addWidget(grp);
}

布局的属性

一个布局有以下几个属性:

  • layoutLeftMargin:该布局与外层的左边间隔
  • layoutTopMargin:该布局与外层的上方间隔
  • layoutRightMargin:该布局与外层的右边间隔
  • layoutBottomMargin:该布局与外层的底部间隔
  • layoutSpacing:该布局中组件之间的间隔
  • layoutStrech:该布局中组件的比例