Qt布局管理器
一、布局管理器介绍
布局管理器(Layout Manager)是在图形用户界面(GUI)应用程序中用于自动管理和排列窗口部件(Widget)的工具。
Qt 共提供了 5 种布局管理器,来帮助开发者方便地组织和管理窗口部件。每种布局管理器对应一个类,分别是 QVBoxLayout(垂直布局)、QHBoxLayout(水平布局)、QGridLayout(网格布局)、QFormLayout(表单布局)和 QStackedLayout(分组布局),继承关系如下图:

1. 顶层基类
QObject
:Qt 所有对象的基类,提供对象树、信号与槽、事件机制等核心功能,让布局类能融入 Qt 对象体系。QLayoutItem
:布局项的抽象基类,定义了布局元素(如控件、子布局)的通用接口(尺寸、位置计算等),让布局系统能统一处理不同 "布局单元"。
2. 核心抽象类:QLayout
继承自 QObject
+ QLayoutItem
,是所有具体布局类的 "父模板",定义了布局的核心逻辑(如添加子项、计算尺寸、设置父部件等),但本身不实现具体布局规则(需子类扩展)。
3. 具体布局子类(常用布局)
QLayout
的子类,实现了不同界面排列规则,是实际开发中直接用的布局:
QBoxLayout
:"盒子布局" 抽象类,分水平 / 垂直两种具体布局:QVBoxLayout
:垂直排列(控件从上到下叠)。QHBoxLayout
:水平排列(控件从左到右排)。
QGridLayout
:网格布局,控件按 行、列 表格化排列,支持跨行 / 跨列。QFormLayout
:表单布局,自动排列 "标签(Label)+ 控件(如输入框)" 的表单结构,适合做设置界面。QStackedLayout
:栈式布局,同一时间只显示 一个页面 (像选项卡切换、向导页),需配合QStackedWidget
用。
二、可视化布局设计
1、Qt布局组件
Qt Designer 支持多种布局管理器,如垂直布局 (QVBoxLayout
)、水平布局 (QHBoxLayout
) 和网格布局 (QGridLayout
)。可以通过右键点击设计区域并选择Layouts
来应用布局管理器。

将布局管理器从工具箱拖拽到设计区域,并把控件放入到布局对应的红色框内部,,控件将被自动排列。
布局属性:

layoutLeftMargin
属性,用来设定布局内部所有子控件与布局左边界之间的固定间距。Margin:边际layoutTopMargin
、layoutRightMargin
和layoutBottomMargin
,分别对应于顶部、右侧和底部的边距控制。layoutSpacing
属性在QVBoxLayout
中用于控制布局内相邻子控件之间的垂直间距。layoutStretch
属性在QVBoxLayout
中用于控制布局内各个子控件在分配剩余空间时的拉伸比例。Stretch:拉伸
2、工具栏按钮
在Qt Designer设计区域的工具栏中,也提供有布局操作按钮,提供便捷操作,如图所示。

三、QVBoxLayout(垂直布局管理器)
垂直布局管理器将所有控件从上到下的顺序依次排列窗口部件。如图,将一组QLabel标签进行垂直方向布局。

实现案例代码如下:
cpp
Widget_02::Widget_02(QWidget *parent) : // 构造函数,参数 parent 指定父窗口
QWidget(parent), // 调用 QWidget 的构造函数
ui(new Ui::Widget_02) // 创建 UI 对象
{
ui->setupUi(this); // 初始化并加载 Qt Designer 生成的 UI 界面
// 创建一个垂直布局管理器,父对象为当前窗口
QVBoxLayout* vlayout = new QVBoxLayout(this);
QLabel* b1 = new QLabel; // 创建第一个标签
QLabel* b2 = new QLabel; // 创建第二个标签
QLabel* b3 = new QLabel; // 创建第三个标签
b1->setStyleSheet("background-color:red"); // 设置 b1 背景色为红色
b2->setStyleSheet("background-color:blue"); // 设置 b2 背景色为蓝色
b3->setStyleSheet("background-color:green"); // 设置 b3 背景色为绿色
vlayout->addWidget(b1); // 将 b1 添加到垂直布局
vlayout->addWidget(b2); // 将 b2 添加到垂直布局
vlayout->addWidget(b3); // 将 b3 添加到垂直布局
vlayout->setSpacing(0); // 设置布局中控件间的间距为 0
vlayout->setContentsMargins(0,0,0,0); // 设置布局外边距为 0(左、上、右、下)
vlayout->setStretch(0,1); // 设置 b1 拉伸比例为 1
vlayout->setStretch(1,2); // 设置 b2 拉伸比例为 2
vlayout->setStretch(2,3); // 设置 b3 拉伸比例为 3
}
🔑 总结
- 垂直布局 :
- 使用
QVBoxLayout
将多个控件垂直排列。 addWidget()
按顺序添加控件。
- 使用
- 控件样式 :
- 使用
setStyleSheet()
设置背景颜色。(StyleSheet层叠样式表)
- 使用
- 布局间距 :
setSpacing(0)
→ 控件之间没有空隙setContentsMargins(0,0,0,0)
→ 布局外边距为 0
- 拉伸比例 :
setStretch(index, ratio)
控制控件在布局中占据空间的比例:- b1:b2:b3 = 1:2:3 → 高度按比例分配
-
参数说明
-
index
- 表示布局中控件的下标(顺序索引),从 0 开始。
- 例如:如果你用
vlayout->addWidget(b1)
添加控件,b1 的下标就是 0,b2 的下标是 1,b3 的下标是 2。
-
stretch(比例)
- 表示该控件在布局中占用剩余空间的相对比例。
- 比例越大,控件分配到的空间就越多。
-
四、QHBoxLayout(水平布局)
水平布局指的是将所有控件从左到右(或者从右到左)依次摆放。如图,将一组QLabel标签进行水平方向布局。

五、QGridLayout(网格布局)
网格布局又称格栅布局或者表格布局,指的是将一些控件按照行和列排列在窗口上。例如:将5个QLabel标签按照行列的方式进行网格布局。

常用函数:
cpp
// 1、添加控件
void addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = Qt::Alignment())
void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan,
Qt::Alignment alignment = Qt::Alignment())
// 2、设置拉伸系数
void setColumnStretch(int column, int stretch) // 给指定列设置拉伸系数
void setRowStretch(int row, int stretch) // 给指定行设置拉伸系数
函数 | 作用 | 参数说明 |
---|---|---|
setColumnStretch() |
设置列的拉伸比例 | column:列索引,stretch:拉伸比例 |
setRowStretch() |
设置行的拉伸比例 | row:行索引,stretch:拉伸比例 |
- 核心思想:按比例分配布局剩余空间,而不会改变控件的最小尺寸或固定尺寸。
- 可以配合 网格布局中的 addWidget() 使用,实现灵活的行列伸缩。
案例:
cpp
Widget_03::Widget_03(QWidget *parent) : // 构造函数,参数 parent 指定父窗口
QWidget(parent), // 调用 QWidget 的构造函数
ui(new Ui::Widget_03) // 创建 UI 对象
{
ui->setupUi(this); // 初始化并加载 Qt Designer 生成的 UI 界面
QGridLayout* glayout = new QGridLayout(this); // 创建一个网格布局,父对象为当前窗口
QLabel* b1 = new QLabel; // 创建标签 b1
QLabel* b2 = new QLabel; // 创建标签 b2
QLabel* b3 = new QLabel; // 创建标签 b3
QLabel* b4 = new QLabel; // 创建标签 b4
QLabel* b5 = new QLabel; // 创建标签 b5
b1->setStyleSheet("background-color:red"); // 设置 b1 背景色为红色
b2->setStyleSheet("background-color:blue"); // 设置 b2 背景色为蓝色
b3->setStyleSheet("background-color:green"); // 设置 b3 背景色为绿色
b4->setStyleSheet("background-color:yellow"); // 设置 b4 背景色为黄色
b5->setStyleSheet("background-color:#abc"); // 设置 b5 背景色为 #abc(浅蓝色)
glayout->addWidget(b1, 0, 0); // b1 放在第 0 行,第 0 列
glayout->addWidget(b2, 0, 1); // b2 放在第 0 行,第 1 列
glayout->addWidget(b3, 1, 0, 1, 2, Qt::AlignCenter);
// b3 放在第 1 行,第 0 列,跨 1 行、2 列,并居中对齐
glayout->addWidget(b4, 2, 0); // b4 放在第 2 行,第 0 列
glayout->addWidget(b5, 2, 1); // b5 放在第 2 行,第 1 列
glayout->setHorizontalSpacing(0); // 设置水平间距为 0
glayout->setVerticalSpacing(0); // 设置垂直间距为 0
}
🔑 总结
- 网格布局(QGridLayout)
- 控件按行列放置,类似表格。
addWidget(widget, row, column)
→ 放置控件到指定行列- 可选参数:
rowSpan
、columnSpan
→ 控件跨多少行多少列 - 可选参数:
alignment
→ 控件对齐方式(居中、左对齐等)
- 控件样式
- 使用
setStyleSheet()
设置背景颜色
- 使用
- 间距
setHorizontalSpacing()
→ 控件列间距setVerticalSpacing()
→ 控件行间距
- 布局效果
- 形成一个 3 行 2 列的网格,b3 跨整行并居中显示
- 每个标签显示不同颜色
六、QFormLayout(表单布局)
一行一行成对的,类似键值对。
QFormLayout
特别适用于将一系列标签和输入控件组织成成对格式的用户界面设计,比如注册页面,每一个输入控件都有一个与之关联的标签。

常用函数:
cpp
// 1、添加控件
// 将指定的 field 控件和存储标签的 label 控件添加到表单布局的末尾
void addRow(QWidget *label, QWidget *field)
// label:标签控件(QLabel)
// field:实际控件(QLineEdit、QComboBox等)
// 功能:把标签和控件组合成一行,添加到表单布局末尾
// 将指定的 field 控件和 labelText 标签添加到表单布局的末尾
void addRow(const QString &labelText, QWidget *field)
// labelText:标签的文字内容(QString),内部会自动创建 QLabel
// field:实际控件
// 功能:更简单,直接用文字创建标签,不必手动创建 QLabel
// 2、设置标签显示格式,默认标签位于控件的左侧
void setRowWrapPolicy(RowWrapPolicy policy)
// policy:标签显示策略,可选值有
// QFormLayout::DontWrapRows → 标签在控件左侧(默认)
// QFormLayout::WrapLongRows → 长标签会换行
// QFormLayout::WrapAllRows → 所有标签显示在控件上方
// 功能:控制表单布局中标签与控件的相对位置
案例:
cpp
Widget_04::Widget_04(QWidget *parent) : // 构造函数,参数 parent 指定父窗口
QWidget(parent), // 调用 QWidget 的构造函数
ui(new Ui::Widget_04) // 创建 UI 对象
{
ui->setupUi(this); // 初始化并加载 Qt Designer 生成的 UI 界面
QFormLayout* flayout = new QFormLayout(this); // 创建表单布局管理器,父对象为当前窗口
flayout->addRow("姓名", new QLineEdit); // 添加一行,左侧标签为"姓名",右侧控件为文本框
flayout->addRow("地址", new QLineEdit); // 添加一行,左侧标签为"地址",右侧控件为文本框
flayout->addRow("邮箱", new QLineEdit); // 添加一行,左侧标签为"邮箱",右侧控件为文本框
flayout->setSpacing(10); // 设置行间距和列间距为 10 像素
flayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
// 设置表单布局策略:标签全部显示在控件上方,而不是默认的左侧
}
布局类型 | 描述 |
---|---|
QFormLayout(表单布局) | 专门用于"标签 + 控件"形式的表单界面,每行通常是一个标签和一个控件。适合数据录入或设置界面。 |
QGridLayout(表格布局) | 类似于二维表格的布局,可以在行和列中放置控件,灵活性更高,不限于标签和控件的组合。 |
七、QStackedLayout((堆栈布局)
QStackedLayout布局管理器可以容纳多个控件或者窗口,但每次只显示其中的一个,如下:

在整个窗口布局中左侧使用QListWidget实现,添加3个子项。右侧则使用QStackedLayout存放3个子窗口,通过堆栈布局可以实现窗口间的切换。
常用函数:
cpp
// 1、添加控件
int addWidget(QWidget *widget)
// 2、设置显示样式
void setStackingMode(StackingMode stackingMode)
stackingMode
:类型是 QStackedLayout::StackingMode
枚举,一般有两个值:
StackOne
(默认)- 一次只显示一个控件,其他控件隐藏。
- 典型用法:选项卡切换界面。
StackAll
- 所有控件都显示在同一位置上(重叠显示)。
- 很少使用,一般用于特殊重叠效果或自定义动画。
案例:
cpp
StackedLayout::StackedLayout(QWidget *parent) : // 构造函数,初始化父窗口
QWidget(parent), // 调用父类 QWidget 的构造函数
ui(new Ui::StackedLayout) // 初始化 UI 指针
{
ui->setupUi(this); // 设置界面
// 水平布局
QHBoxLayout* hlayout = new QHBoxLayout(this); // 创建水平布局管理器,并设置为窗口的主布局
QListWidget* listWidget = new QListWidget; // 创建列表控件,用于选择页面
listWidget->addItem("窗口一"); // 添加列表项 "窗口一"
listWidget->addItem("窗口二"); // 添加列表项 "窗口二"
listWidget->addItem("窗口三"); // 添加列表项 "窗口三"
hlayout->addWidget(listWidget,1); // 将列表控件添加到水平布局,占 1 份比例
// 堆栈布局
QStackedLayout* slayout = new QStackedLayout; // 创建堆栈布局管理器,用于显示多个页面
page1* p1= new page1; // 创建自定义页面 1
Page2* p2= new Page2; // 创建自定义页面 2
Page3* p3= new Page3; // 创建自定义页面 3
slayout->addWidget(p1); // 将页面 1 添加到堆栈布局
slayout->addWidget(p2); // 将页面 2 添加到堆栈布局
slayout->addWidget(p3); // 将页面 3 添加到堆栈布局
hlayout->addLayout(slayout,4); // 将堆栈布局添加到水平布局,占 4 份比例
// 连接信号和槽,实现点击列表项切换堆栈布局显示的页面
connect(listWidget, &QListWidget::currentRowChanged, slayout, &QStackedLayout::setCurrentIndex);
}
- QListWidget 是 Qt 提供的一个列表控件(列表视图) ,继承自
QListView
。就是一个 竖着排列、可点击选择的条目列表控件。
元素 | 作用 |
---|---|
listWidget |
用户点击的列表,发出当前行索引信号 currentRowChanged(int) |
slayout |
堆栈布局,根据索引显示对应页面,槽函数 setCurrentIndex(int) |
connect | 将信号和槽直接连接,实现点击列表项切换页面 |
- 信号发出行索引,槽函数接收索引切换页面,因为参数类型匹配,所以直接连接就能实现"点击左边列表 → 显示右边对应页面",完全不需要额外写槽函数。
💡为什么不需要显式写槽函数
1. 信号和槽的本质
在 Qt 中:
connect(sender, &Sender::signal, receiver, &Receiver::slot);
- sender 发出信号
- receiver 响应信号
- slot 是槽函数,用来处理信号的逻辑
槽函数可以是自定义的成员函数 ,也可以是 Qt 自带的公共函数,只要参数类型匹配即可。
2. 参数匹配原则
你的代码是:
connect(listWidget, &QListWidget::currentRowChanged,
slayout, &QStackedLayout::setCurrentIndex);
- 信号:
currentRowChanged(int currentRow)
→ 发出一个 int - 槽函数:
setCurrentIndex(int index)
→ 接收一个 int
💡 关键点:
Qt 的信号槽机制允许信号直接连接到已有的公共成员函数,只要参数类型匹配即可。
也就是说,你不必写一个自定义槽函数去"取信号的值然后再调用 setCurrentIndex",因为 Qt 已经帮你把参数传给了 setCurrentIndex
。