文章目录
- [1. 容器类控件](#1. 容器类控件)
-
- [1.1 Group Box](#1.1 Group Box)
- [1.2 Tab Widget](#1.2 Tab Widget)
- [2. 布局管理器](#2. 布局管理器)
-
- [2.1 垂直布局](#2.1 垂直布局)
- [2.2 水平布局](#2.2 水平布局)
- [2.3 网格布局](#2.3 网格布局)
- [2.4 表单布局](#2.4 表单布局)
- [2.5 Spacer](#2.5 Spacer)
1. 容器类控件
多元素控件,包含的内容,是一个一个的自定义好的 "Item" 对象
容器类控件,包含的内容是前面已经学过的各种控件了,QPushButton、QLineEdit、QLabel 等...
这里我们主要介绍两个:
- QGroupBox 分组框
- QTabWidget 标签页
1.1 Group Box
使用 QGroupBox 实现一个带有标题的分组框. 可以把其他的控件放到里面作为一组. 这样看起来能更好看一点.
注意, 不要把 QGroupBox 和 QButtonGroup 混淆. (之前在介绍 QRadionButton 的时候提到了 QButtonGroup ).

就只是为了让界面看起来更好看一点~~
当一个界面比较复杂的时候,包含了很多控件的时候,分组框就可以把具有关联关系的控件,组织到一起,
核心属性
| 属性 | 说明 |
|---|---|
| title | 分组框的标题 |
| alignment | 分组框内部内容的对齐方式 |
| flat | 是否是 "扁平" 模式 |
| checkable | 是否可选择. 设为 true, 则在 title 前方会多出一个可勾选的部分. |
| checked | 描述分组框的选择状态 (前提是 checkable 为 true) |
分组框只是一个用来 "美化界面" 这样的组件, 并不涉及到用户交互和业务逻辑. 属于 "锦上添花" .
代码示例:给麦当劳案例加上分组框
在界面上创建三个分组框, 并且在分组框内部创建下拉框和微调框.

编写 widget.cpp, 添加初始化下拉框的代码
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->comboBox->addItem("巨无霸");
ui->comboBox->addItem("⻨辣鸡腿堡");
ui->comboBox_2->addItem("薯条");
ui->comboBox_2->addItem("麦乐鸡块");
ui->comboBox_3->addItem("可乐");
ui->comboBox_3->addItem("雪碧");
}
运行结果:

将第一个分组框中的属性勾选后,运行查看效果

运行结果:

1.2 Tab Widget
使用 QTabWidget 实现一个带有标签页的控件, 可以往里面添加一些 widget. 进一步的就可以通过标签页来切换.
核心属性
| 属性 | 说明 |
|---|---|
| tabPosition | 标签页所在的位置. + North 上方 + South 下方 + West 左侧 + East 右侧 |
| currentIndex | 当前选中了第几个标签页 (从 0 开始计算) |
| currentTabText | 当前选中的标签页的文本 |
| currentTabName | 当前选中的标签页的名字 |
| currentTabIcon | 当前选中的标签页的图标 |
| currentTabToolTip | 当前选中的标签页的提示信息 |
| tabsCloseable | 标签页是否可以关闭 |
| movable | 标签页是否可以移动 |
核心信号
| 属性 | 说明 |
|---|---|
| currentChanged(int) | 在标签页发生切换时触发, 参数为被点击的选项卡编号. |
| tabBarClicked(int) | 在点击选项卡的标签条的时候触发. 参数为被点击的选项卡编号. |
| tabBarDoubleClicked(int) | 在双击选项卡的标签条的时候触发. 参数为被点击的选项卡编号. |
| tabCloseRequest(int) | 在标签页关闭时触发. 参数为被关闭的选项卡编号 |
代码示例:使用标签页管理多组控件
在界面上创建一个 QTabWidget , 和两个按钮,按钮的 objectName 为 pushButton_add 和 pushButton_remove

注意,
- QTabWidget 中的每个标签页都是一个 QWidget
- 点击标签页, 就可以直接切换.
- 右键 QTabWidget , 可以添加标签页或者删除标签页.
编写 widget.cpp, 进行初始化, 给标签页中放个简单的 label
- 注意新创建的 label 的父元素, 是 ui->tab 和 ui->tab_2 . Qt 中使用父子关系决定该控件 "在哪里"
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLabel* label1 = new QLabel(ui->tab);
label1->setText("标签页1");
label1->resize(100, 50);
QLabel* label2 = new QLabel(ui->tab_2);
label2->setText("标签页2");
label2->resize(100, 50);
}
编写按钮的 slot 函数
- 使用 count() 获取到标签页的个数.
- 使用 addTab 新增标签页.
- 使用 removeTab 删除标签页.
- 使用 currentIndex 获取到当前标签页的下标.
- 使用 setCurrentIndex 切换当前标签页.
cpp
void Widget::on_pushButton_add_clicked()
{
// 获取当前有几个标签页
int count = ui->tabWidget->count();
// 创建新的 widget
QWidget* w = new QWidget();
ui->tabWidget->addTab(w, QString("Tab ") + QString::number(count+1));
// 给 widget 中添加 label
QLabel* label = new QLabel(w);
label->setText(QString("标签页") + QString::number(count+1));
label->resize(100, 50);
// 选中这个新的标签页
ui->tabWidget->setCurrentIndex(count);
}
void Widget::on_pushButton_remove_clicked()
{
// 获取当前标签页的下标
int index = ui->tabWidget->currentIndex();
// 删除当前标签页
ui->tabWidget->removeTab(index);
}
编写 QTabWidget 的 currentChanged 函数
cpp
void Widget::on_tabWidget_currentChanged(int index)
{
qDebug() << "当前选中标签页为: " << index;
}
运行结果:

- 点击新建标签页, 可以创建出新的标签.
- 点击删除当前标签页, 可以删除标签.
- 切换标签页时, 可以看到 qDebug 打印出的标签页编号.
2. 布局管理器
之前使用 Qt 在界面上创建的控件, 都是通过 "绝对定位" 的方式来设定的.
也就是每个控件所在的位置, 都需要计算坐标, 最终通过 setGeometry 或者 move 方式摆放过去,这种设定方式其实并不方便. 尤其是界面如果内容比较多, 不好计算. 而且一个窗口大小往往是可以调整的, 按照绝对定位的方式, 也无法自适应窗口大小.
因此 Qt 引入 "布局管理器" (Layout) 机制, 来解决上述问题.
当然, 布局管理器并非 Qt 独有. 其他的 GUI 开发框架, 像 Android, 前端等也有类似的机制.
2.1 垂直布局
使用 QVBoxLayout 表示垂直的布局管理器. V 是 vertical 的缩写.
核心属性
| 属性 | 说明 |
|---|---|
| layoutLeftMargin | 左侧边距 |
| layoutRightMargin | 右侧边距 |
| layoutTopMargin | 上方边距 |
| layoutBottomMargin | 下方边距 |
| layoutSpacing | 相邻元素之间的间距 |
Layout 只是用于界面布局, 并没有提供信号.
代码示例:使用 QVBoxLayout 管理多个控件.
编写代码, 创建布局管理器和三个按钮. 并且把按钮添加到布局管理器中.
- 使用 addWidget 把控件添加到布局管理器中.
- 使用 setLayout 设置该布局管理器到 widget 中.
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建3个按钮
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
// 创建布局管理器, 并且把按钮添加进去
// 如果创建的时候指定⽗元素为 this, 则后面不需要 setLayout ⽅法了.
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
// 把布局管理器设置到 widget 中
this->setLayout(layout);
}
运行程序, 可以看到此时界面上的按钮就存在于布局管理器中. 随着窗口尺寸变化而发生改变.
注意:此时三个按钮的尺寸和位置, 都是自动计算出来的.

通过上述代码的方式, 只能给这个 widget 设定一个布局管理器. 实际上也可以通过 Qt Design 在一个窗口中创建多个布局管理器.
代码示例:创建两个 QVBoxLayout
在界面上创建两个 QVBoxLayout , 每个 QVBoxLayout 各放三个按钮

运行程序, 可以看到这些按钮已经自动排列好. 只不过当前这些按钮的位置不能随着窗口大小自动变化.

通过 Qt Designer 创建的布局管理器, 其实是先创建了一个 widget, 设置过 geometry 属性的. 再把这个 layout 设置到这个 widget 中.
实际上, 一个 widget 只能包含一个 layout.
打开 ui 文件的原始 xml, 可以看到其中的端倪.
这种情况下 layout 并非是窗口 widget 的布局管理器, 因此不会随着窗口大小改变.
xml
<?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>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>160</x>
<y>120</y>
<width>161</width>
<height>301</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="verticalLayoutWidget_2">
<property name="geometry">
<rect>
<x>460</x>
<y>120</y>
<width>161</width>
<height>301</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_6">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
结构如下:
plain
主Widget (name="Widget")
├── 子Widget1 (name="verticalLayoutWidget")
│ └── 布局1 (class="QVBoxLayout" name="verticalLayout")
│ ├── pushButton_2
│ ├── pushButton_3
│ └── pushButton
└── 子Widget2 (name="verticalLayoutWidget_2")
└── 布局2 (class="QVBoxLayout" name="verticalLayout_2")
├── pushButton_4
├── pushButton_5
└── pushButton_6
- 外层主窗口的固定大小
在 <widget class="QWidget" name="Widget">下,直接定义了其 geometry属性。这是主窗口的固定大小和位置,但这里没有直接设置顶级的 layout>。因此,主窗口默认没有布局管理器,内部的控件位置固定。
- 作为"布局容器"的中间控件 (verticalLayoutWidget)
为了实现布局,Qt Designer 创建了一个中间控件来承载布局管理器。
- 步骤一:创建承载控件 :创建了一个名为
verticalLayoutWidget的QWidget控件。 - 步骤二:设置固定几何属性 :为该控件指定了固定 的位置和大小 (
geometry)。这个控件被直接放置在主窗口中。 - 步骤三:设置布局管理器 :在这个
verticalLayoutWidget控件内部 ,设置了QVBoxLayout布局管理器verticalLayout。 - 步骤四:向布局中添加子控件 :布局管理器
verticalLayout包含了三个QPushButton。
另一个 verticalLayoutWidget_2结构完全相同,只是名称和位置不同。
综上:
- 真正的布局管理器是
verticalLayout,它属于verticalLayoutWidget。 verticalLayoutWidget在主窗口中的位置和大小 (x:160, y:120, w:161, h:301) 是绝对固定的。它本身是主窗口的一个普通子控件。- 当改变主窗口
Widget的大小时:- 其内部的子控件
verticalLayoutWidget和verticalLayoutWidget_2的位置和大小不会自动调整,因为它们没有被任何布局管理器管理。 - 虽然
verticalLayoutWidget内部的按钮 (pushButton_2等) 在verticalLayout的管理下,会随verticalLayoutWidget的大小变化而调整(例如通过代码手动改变verticalLayoutWidget的geometry),但verticalLayoutWidget本身在主窗口中是"固定"的。
- 其内部的子控件

如果希望整个窗口的内容能自动调整,应该直接为顶层窗口( Widget)设置布局管理器。

运行结果:

2.2 水平布局
使用 QHBoxLayout 表示水平的布局管理器. H 是 horizontal 的缩写.
核心属性 (和 QVBoxLayout 属性是一致的)
| 属性 | 说明 |
|---|---|
| layoutLeftMargin | 左侧边距 |
| layoutRightMargin | 右侧边距 |
| layoutTopMargin | 上方边距 |
| layoutBottomMargin | 下方边距 |
| layoutSpacing | 相邻元素之间的间距 |
代码示例:使用 QHBoxLayout 管理控件
编写代码, 创建布局管理器和三个按钮. 并且把按钮添加到布局管理器中.
cpp
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);
}
运行程序, 可以看到此时界面上的按钮就存在于布局管理器中. 随着窗口尺寸变化而发生改变.
此时三个按钮的尺寸和位置, 都是自动计算出来的.

Layout 里面可以再嵌套上其他的 layout, 从而达到更复杂的布局效果.
代码示例:嵌套的 layout
在代码中创建以下内容
- 使用 addLayout 给 layout 中添加子 layout.
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建垂直的布局管理器
QVBoxLayout* vlayout = new QVBoxLayout();
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);
}
运行结果:

结合 QHBoxLayout 和 QVBoxLayout , 就可以做出各种复杂的界面了.
2.3 网格布局
Qt 中还提供了 QGridLayout 用来实现网格布局的效果. 可以达到 M * N 的这种网格的效果.
核心属性
整体和 QVBoxLayout 以及 QHBoxLayout 相似. 但是设置 spacing 的时候是按照垂直水平两个方向来设置的.
| 属性 | 说明 |
|---|---|
| layoutLeftMargin | 左侧边距 |
| layoutRightMargin | 右侧边距 |
| layoutTopMargin | 上方边距 |
| layoutBottomMargin | 下方边距 |
| layoutHorizontalSpacing | 相邻元素之间水平方向的间距 |
| layoutVerticalSpacing | 相邻元素之间垂直方向的间距 |
| layoutRowStretch | 行方向的拉伸系数 |
| layoutColumnStretch | 列方向的拉伸系数 |
代码示例:使用 QGridLayout 管理元素
代码中创建 QGridLayout 和 4 个按钮.
- 使用 addWidget 添加控件到布局管理器中. 但是添加的同时会指定两个坐标. 表示放在第几行, 第几列.
cpp
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);
setLayout(layout);
}
运行结果:

如果调整行列坐标为下列代码
cpp
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 0, 1);
layout->addWidget(button3, 0, 2);
layout->addWidget(button4, 0, 3);
执行代码, 可以看到这几个按钮都在同一行了. 相当于 QHBoxLayout

如果调整行列坐标为下列代码
cpp
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 1, 0);
layout->addWidget(button3, 2, 0);
layout->addWidget(button4, 3, 0);
执行代码, 可以看到这几个按钮都在同一列了. 相当于 QVBoxLayout

任意调整行列, 即可看到不同的效果
cpp
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 1, 1);
layout->addWidget(button3, 2, 2);
layout->addWidget(button4, 3, 3);

编写代码形如
cpp
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 1, 0);
layout->addWidget(button3, 2, 0);
layout->addWidget(button4, 10, 0);
此处也要注意, 设置行和列的时候, 如果设置的是一个很大的值, 但是这个值和上一个值之间并没有其他的元素, 那么并不会在中间腾出额外的空间.
虽然把 button4 设置在第 10 行, 但是由于 3-9 行没有元素. 因此 button4 仍然会紧挨在 button3 下方. 看起来和上面的 0 1 2 3 的情况是相同的.

代码示例:设置 QGridLayout 中元素的大小比例.
创建 6 个按钮, 按照 2 行 3 列的方式排列
- 使用 setColumnStretch 设置每一列的拉伸系数.
cpp
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");
QPushButton* button5 = new QPushButton("按钮5");
QPushButton* button6 = new QPushButton("按钮6");
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 0, 1);
layout->addWidget(button3, 0, 2);
layout->addWidget(button4, 1, 0);
layout->addWidget(button5, 1, 1);
layout->addWidget(button6, 1, 2);
setLayout(layout);
// 第 0 列拉伸比例设为 1;
layout->setColumnStretch(0, 1);
// 第 1 列拉伸比例设为 0, 即为固定大小, 不参与拉伸
layout->setColumnStretch(1, 0);
// 第 2 列拉伸比例设为 2, 即为第 2 列的宽度是第 0 列的 2 倍
layout->setColumnStretch(2, 2);
}
执行程序, 可以看到每一列的宽度是不同的. 并且随着窗口调整动态变化.

另外, QGridLayout 也提供了 setRowStretch 设置行之间的拉伸系数. 上述案例中, 直接设置 setRowStretch 效果不明显, 因为每个按钮的高度是固定的. 需要把按钮的垂直方向的 sizePolicy 属性设置为 QSizePolicy::Expanding 尽可能填充满布局管理器, 才能看到效果.
代码示例:设置垂直方向的拉伸系数
编写代码, 创建 6 个按钮, 按照 3 行 2 列方式排列.
使用 setSizePolicy 设置按钮的尺寸策略. 可选的值如下:
- QSizePolicy::Ignored : 忽略控件的尺寸,不对布局产生影响。
- QSizePolicy::Minimum : 控件的最小尺寸为固定值,布局时不会超过该值。
- QSizePolicy::Maximum : 控件的最大尺寸为固定值,布局时不会小于该值。
- QSizePolicy::Preferred : 控件的理想尺寸为固定值,布局时会尽量接近该值。
- QSizePolicy::Expanding : 控件的尺寸可以根据空间调整,尽可能占据更多空间。
- QSizePolicy::Shrinking : 控件的尺寸可以根据空间调整,尽可能缩小以适应空间。
cpp
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");
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);
// 把 layout 设置到窗口中
this->setLayout(layout);
// 设置拉伸系数
layout->setRowStretch(0, 1);
layout->setRowStretch(1, 0);
layout->setRowStretch(2, 2);
}
执行代码, 观察效果.
此时的按钮垂直方向都舒展开了. 并且调整窗口尺寸, 也会按照设定的比例同步变化.

总的来说, 使用 QGridLayout 能够代替很多 QHBoxLayout 和 QVBoxLayout 嵌套的场景. 毕竟嵌套的代码写起来是比较麻烦的.
另外不要忘了, QGridLayout 里面也能嵌套 QHBoxLayout 和 QVBoxLayout , QHBoxLayout 和 QVBoxLayout 里面也能嵌套 QGridLayout . 灵活使用上述布局管理器, 就可以实现出任意的复杂界面.
2.4 表单布局
除了上述的布局管理器之外, Qt 还提供了 QFormLayout , 属于是 QGridLayout 的特殊情况, 专门用于实现两列表单的布局.
这种表单布局多用于让用户填写信息的场景. 左侧列为提示, 右侧列为输入框
代码示例:使用 QFormLayout 创建表单.
编写代码, 创建 QFormLayout , 以及三个 label 和三个 lineEdit
- 使用 addRow 方法来添加一行. 每行包含两个控件. 第一个控件固定是 QLabel / 文本, 第二个控件则可以是任意控件.
- 如果把第一个参数填写为 NULL, 则什么都不显示.
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QFormLayout* layout = new QFormLayout();
setLayout(layout);
// 创建 3 个 label 作为第一列
QLabel* label1 = new QLabel("姓名");
QLabel* label2 = new QLabel("年龄");
QLabel* label3 = new QLabel("电话");
// 创建 3 个 输入框 作为第二列
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);
}
运行结果:

2.5 Spacer
使用布局管理器的时候, 可能需要在控件之间, 添加一段空白. 就可以使用 QSpacerItem 来表示.
核心属性
| 属性 | 说明 |
|---|---|
| width | 宽度 |
| height | 高度 |
| hData | 水平方向的 sizePolicy + QSizePolicy::Ignored : 忽略控件的尺寸,不对布局产生影响。 + QSizePolicy::Minimum : 控件的最小尺寸为固定值,布局时不会超过该值。 + QSizePolicy::Maximum : 控件的最大尺寸为固定值,布局时不会小于该值。 + QSizePolicy::Preferred : 控件的理想尺寸为固定值,布局时会尽量接近该值。 + QSizePolicy::Expanding : 控件的尺寸可以根据空间调整,尽可能占据更多空间。 + QSizePolicy::Shrinking : 控件的尺寸可以根据空间调整,尽可能缩小以适应空间。 |
| vData | 垂直方向的 sizePolicy 选项同上. |
上述属性在构造函数设置即可.
代码示例:创建一组左右排列的按钮.
在界面上创建一个 QHBoxLayout , 并添加两个按钮.
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QHBoxLayout* layout = new QHBoxLayout();
setLayout(layout);
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
layout->addWidget(button1);
layout->addWidget(button2);
}
直接运行程序, 可以看到两个按钮是紧挨着的.

在两个按钮中间添加一个 spacer
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QHBoxLayout* layout = new QHBoxLayout();
setLayout(layout);
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
// 创建 spacer 使两个按钮之间存在空白.
QSpacerItem* spacer = new QSpacerItem(200, 20);
// 当前是要把空白添加到两个按钮之间. 此处 add 的顺序就是把 addSpacerItem 放到中间了.
layout->addWidget(button1);
layout->addSpacerItem(spacer);
layout->addWidget(button2);
}
运行程序, 观察代码效果. 可以看到两个按钮之间已经存在了间隔了.
调整 QSpacerItem 不同的尺寸, 即可看到不同的间距.

在 Qt Designer 中, 也可以直接给界面上添加 spacer

上述的每个控件,都是"可扩展的"每个控件都是对应 Qt 内置的一个类.
咱们在代码中都可以基于这个类,继承出你自定义的子类~
在这个自定义的子类中, 又可以漆加很多的属性和方法,实现你自己的需求场景,还可以在子类中,把多个控件组合到一起~~