
在 Qt GUI 开发中,界面排版是影响用户体验的关键环节。如果直接用
setGeometry或move进行 “绝对定位”,不仅控件位置计算繁琐,还无法自适应窗口大小调整 —— 这时候,Qt 的布局管理器(Layout)就能完美解决问题!布局管理器能自动计算控件位置和尺寸,支持窗口缩放自适应、控件间距统一、复杂界面嵌套,是 Qt 界面开发的 “排版神器”。 本文基于 Qt 5.14 版本,全面拆解 5 大核心布局管理器(垂直布局、水平布局、网格布局、表单布局、Spacer 空白控件),从基础属性到实战案例,再到避坑指南,带你从零掌握 Qt 界面的标准化排版技巧,让你的界面既美观又灵活!下面就让我们正式开始吧!
在没有布局管理器的时候,开发者需要手动计算每个控件的x、y坐标和宽高,一旦窗口大小改变或控件增减,整个界面就会错乱。而 Qt 的布局管理器带来了三大核心优势:
Qt 提供的 5 大核心布局管理器各有侧重,覆盖所有排版场景:
接下来,我们将逐一详解每个布局的用法,搭配完整 C++ 代码示例,让你看完就能上手。
在学习具体布局之前,先掌握布局管理器的通用规则和核心 API,所有布局都基于这些基础逻辑:
无论哪种布局,都离不开以下核心操作,统一称为 “布局三步骤”:
QVBoxLayout);addWidget添加控件,用addLayout添加子布局;setLayout将布局绑定到窗口或容器控件(如QWidget、QGroupBox)。通用核心 API:
API 方法 | 功能说明 | 实用场景 |
|---|---|---|
addWidget(QWidget *widget) | 向布局中添加控件 | 基础控件排版 |
addLayout(QLayout *layout) | 向布局中添加子布局 | 复杂界面嵌套 |
setMargin(int margin) | 设置布局四周的边距(已过时,推荐用setContentsMargins) | 统一窗口边距 |
setContentsMargins(int left, int top, int right, int bottom) | 分别设置左、上、右、下边距 | 精细控制边距 |
setSpacing(int spacing) | 设置控件之间的间距 | 统一控件间距 |
addSpacing(int size) | 在布局中添加固定大小的空白 | 手动调整局部间距 |
addStretch(int stretch = 1) | 添加拉伸因子,占据多余空间 | 控件对齐(如靠右、靠下) |
setStretchFactor(QWidget *widget, int stretch) | 设置控件的拉伸权重 | 控制控件缩放比例 |
QWidget),否则无法生效 —— 容器的大小变化会驱动布局重新计算。QVBoxLayout 是最常用的布局之一,控件按垂直方向从上到下依次排列,适用于 “单列控件” 场景(如菜单列表、垂直按钮组、表单分组)。

垂直布局的核心属性继承自QLayout,重点关注以下实用 API:
API 方法 | 功能说明 | 实用场景 |
|---|---|---|
addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = 0) | 添加控件,可指定拉伸因子和对齐方式 | 控制单个控件的缩放权重和对齐 |
insertWidget(int index, QWidget *widget) | 在指定位置插入控件 | 动态调整控件顺序 |
setAlignment(Qt::Alignment alignment) | 设置布局内所有控件的整体对齐方式 | 如所有控件居中、靠右排列 |
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建三点按钮,使用垂直布局管理器管理起来
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
//创建布局管理器
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
//把布局管理器添加到窗口中
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}运行结果:

运行效果:三个按钮垂直排列,窗口缩放时按钮宽度自适应。
通过在界面中添加多个VBoxLayout控件,实现分组控制控件缩放。示例:

运行结果如下:

setFixedHeight设置固定高度,或setSizePolicy设置尺寸策略;geometry,可能覆盖布局边距,建议容器控件不手动设置位置和尺寸,完全由布局管理;QHBoxLayout 与垂直布局对称,控件按水平方向从左到右排列,适用于 “单行控件” 场景(如工具栏、导航栏、水平按钮组、搜索框组合)。

水平布局的 API 与垂直布局完全一致,仅排列方向不同,重点关注:
API 方法 | 功能说明 | 实用场景 |
|---|---|---|
setAlignment(Qt::Alignment alignment) | 整体对齐方式(如Qt::AlignRight靠右排列) | 工具栏按钮靠右、搜索框居中 |
addStretch(int stretch) | 添加水平拉伸因子 | 挤压控件到左侧 / 右侧 |
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QHBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}运行结果如下:

通过布局嵌套,实现 “水平布局包含垂直子布局” 的复杂界面。
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建垂直的布局管理器
QVBoxLayout* vlayout = new QVBoxLayout();
this->setLayout(vlayout);
//添加两个按钮进去
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
vlayout->addWidget(button1);
vlayout->addWidget(button2);
//创建水平的布局管理器
QHBoxLayout* hlayout = new QHBoxLayout();
//添加两个按钮进去
QPushButton* button3 = new QPushButton("按钮3");
QPushButton* button4 = new QPushButton("按钮4");
hlayout->addWidget(button3);
hlayout->addWidget(button4);
//把水平布局管理器添加到垂直布局管理器内部
vlayout->addLayout(hlayout);
}
Widget::~Widget()
{
delete ui;
}运行结果如下:

setFixedWidth或setSizePolicy设置;QGridLayout 是功能最强大的布局,控件按 “行列坐标” 排列,支持跨行列布局,适用于复杂的多行列界面(如表格数据展示、表单混合排版、工具面板)。
网格布局的核心是 “行列坐标” 和 “拉伸系数”,关键 API 如下:
API 方法 | 功能说明 | 实用场景 |
|---|---|---|
addWidget(QWidget *widget, int row, int column, int rowSpan = 1, int columnSpan = 1) | 添加控件到指定行列,支持跨行列(rowSpan = 跨行数,columnSpan = 跨列数) | 复杂网格排版(如标题跨 2 列) |
setRowStretch(int row, int stretch) | 设置行拉伸系数 | 控制行的缩放权重 |
setColumnStretch(int column, int stretch) | 设置列拉伸系数 | 控制列的缩放权重 |
setRowMinimumHeight(int row, int minHeight) | 设置行最小高度 | 固定行高,避免过度压缩 |
setColumnMinimumWidth(int column, int minWidth) | 设置列最小宽度 | 固定列宽,避免过度压缩 |
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QGridLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
QPushButton* button4 = new QPushButton("按钮4");
QGridLayout* layout = new QGridLayout();
// layout->addWidget(button1, 0, 0);
// layout->addWidget(button2, 0, 1);
// layout->addWidget(button3, 1, 0);
// layout->addWidget(button4, 1, 1);
//相当于水平布局
//此时大家的行数只要是一样的即可,不一定非得是0
// layout->addWidget(button1, 0, 0);
// layout->addWidget(button2, 0, 1);
// layout->addWidget(button3, 0, 2);
// layout->addWidget(button4, 0, 3);
//相当于垂直布局
//此时大家的列数只要是一样的即可,不一定非得是0
// layout->addWidget(button1, 0, 0);
// layout->addWidget(button2, 1, 0);
// layout->addWidget(button3, 2, 0);
// layout->addWidget(button4, 3, 0);
// 每个按钮独占一行和一列
//此处设置的行数和列数只是用来决定控件之间的相对位置
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 1, 1);
layout->addWidget(button3, 2, 2);
layout->addWidget(button4, 3, 3);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}运行结果:

运行效果:2 行 2 列的表单布局,标签列宽度固定,输入框列随窗口缩放拉伸,水平和垂直间距分开设置。
编写代码:
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QGridLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建6个按钮,按照3行2列的方式进行排列
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
QPushButton* button4 = new QPushButton("按钮4");
QPushButton* button5 = new QPushButton("按钮5");
QPushButton* button6 = new QPushButton("按钮6");
// 设置按钮的SizePolicy为可拉伸,否则默认垂直方向不可拉伸,水平方向才能拉伸
button1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//创建layout并把按钮添加进去
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 0, 1);
layout->addWidget(button3, 1, 0);
layout->addWidget(button4, 1, 1);
layout->addWidget(button5, 2, 0);
layout->addWidget(button6, 2, 1);
this->setLayout(layout);
//设置垂直方向拉伸系数 —— 高度方向比例为1:1:2
layout->setRowStretch(0, 1);
layout->setRowStretch(1, 1);
layout->setRowStretch(2, 2);
}
Widget::~Widget()
{
delete ui;
}运行结果:

addWidget的跨行列参数是rowSpan(跨行数)在前,columnSpan(跨列数)在后,不要颠倒;setFixedSize固定控件大小,拉伸系数无效;setHorizontalSpacing和setVerticalSpacing分别设置水平和垂直间距,避免行列间距统一导致界面拥挤。QFormLayout 是网格布局的 “简化版”,专门用于两列表单(左侧标签 + 右侧输入控件),无需手动设置行列坐标,自动对齐标签和输入控件,适用于登录界面、注册表单、配置页面等场景。
表单布局的核心是 “行”,每行包含 “标签 + 字段”(字段可以是输入框、下拉框等控件),关键 API:
API 方法 | 功能说明 | 实用场景 |
|---|---|---|
addRow(const QString &labelText, QWidget *fieldWidget) | 添加一行(标签文本 + 字段控件) | 快速创建表单行 |
addRow(QWidget *labelWidget, QWidget *fieldWidget) | 添加一行(标签控件 + 字段控件) | 自定义标签样式(如带图标的标签) |
addRow(QWidget *fieldWidget) | 添加一行(仅字段控件,跨两列) | 添加按钮、提示信息等跨列控件 |
setLabelAlignment(Qt::Alignment alignment) | 设置所有标签的对齐方式 | 标签文本右对齐(表单常用) |
setFieldGrowthPolicy(FieldGrowthPolicy policy) | 设置字段控件的增长策略 | 控制字段是否拉伸(如ExpandingFieldGrowth) |
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QFormLayout>
#include <QLineEdit>
#include <QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置成3行2列
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
//创建3个label作为第一列
QLabel* label1 = new QLabel("姓名");
QLabel* label2 = new QLabel("年龄");
QLabel* label3 = new QLabel("电话");
//创建3个linedit作为第二列
QLineEdit* edit1 = new QLineEdit();
QLineEdit* edit2 = new QLineEdit();
QLineEdit* edit3 = new QLineEdit();
//把上述控件添加到表单布局中
layout->addRow(label1, edit1);
layout->addRow(label2, edit2);
layout->addRow(label3, edit3);
//创建一个提交按钮
QPushButton* button = new QPushButton("提交");
layout->addRow(nullptr, button);
}
Widget::~Widget()
{
delete ui;
}运行结果:

setLabelAlignment(Qt::AlignRight)让标签右对齐,避免对齐混乱;setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow)开启拉伸;setSpacing控制行间距,建议设置 20-30px,避免控件过于拥挤。Spacer(空白控件)是布局管理器的 “辅助神器”,用于填充多余空间、调整控件间距、控制控件对齐,分为水平 Spacer(QSpacerItem::Horizontal)和垂直 Spacer(QSpacerItem::Vertical)。
Spacer 的核心是 “尺寸策略”,通过QSpacerItem创建,关键参数:
构造函数参数 | 功能说明 | 实用场景 |
|---|---|---|
int width, int height | Spacer 的最小宽度和高度 | 固定空白大小 |
QSizePolicy::Policy hPolicy | 水平尺寸策略(如Expanding) | 水平方向拉伸填充 |
QSizePolicy::Policy vPolicy | 垂直尺寸策略(如Expanding) | 垂直方向拉伸填充 |
常用尺寸策略:
QSizePolicy::Fixed:固定大小,不拉伸;QSizePolicy::Expanding:拉伸填充多余空间;QSizePolicy::Minimum:最小尺寸,不拉伸;QSizePolicy::Maximum:最大尺寸,不拉伸。#include "widget.h"
#include "ui_widget.h"
#include <QSpacerItem>
#include <QPushButton>
#include <QHBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QHBoxLayout* layout = new QHBoxLayout();
this->setLayout(layout);
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
//创建一个spacer,使得两个按钮之间存在空白
QSpacerItem* spacer = new QSpacerItem(200, 20);
//当前是要把空白添加到两个按钮之间
layout->addWidget(button1);
layout->addSpacerItem(spacer);
layout->addWidget(button2);
}
Widget::~Widget()
{
delete ui;
}运行结果:

Expanding,否则 Spacer 仅显示固定大小;setSpacing,Spacer 适用于 “局部特殊间距” 或 “控件对齐”,过度使用会增加代码复杂度。geometry;QWidget),容器不手动设置位置和尺寸,完全由布局管理。setMinimumSize设置控件最小尺寸,或减小布局边距 / 间距。setFixedSize固定大小,或窗口没有多余空间;setFixedSize,或确保窗口可缩放,给拉伸因子留出作用空间。addStretch,复杂的局部间距调整用 Spacer;QGroupBox、QTabWidget等容器控件包裹布局,美化界面并提升逻辑性。掌握布局管理器后,你将彻底告别 “控件错位”“窗口缩放错乱” 的烦恼,开发出既美观又灵活的 Qt 界面。如果本文对你有帮助,欢迎点赞、收藏、转发,如有疑问或建议,欢迎在评论区留言交流~