目录
[二,Group Box](#二,Group Box)
[2.1 主要属性](#2.1 主要属性)
[2.2 点餐系统再升级](#2.2 点餐系统再升级)
[三,Tab Widget](#三,Tab Widget)
[3.1 主要属性](#3.1 主要属性)
[3.2 代码示例](#3.2 代码示例)
[4.1 垂直布局](#4.1 垂直布局)
[4.2 水平布局](#4.2 水平布局)
[4.3 网格布局](#4.3 网格布局)
[4.4 拉伸系数](#4.4 拉伸系数)
[4.5 表单布局](#4.5 表单布局)
一,关于容器类控件
容器类控件指的就是这个容器内可以容纳一些其它的控件
不同于多元素控件,多元素控件包含的是一个一个自定义好的 "item" 对象;而容器内控件包含的直接就是我们前面介绍的一堆的控件
二,Group Box
2.1 主要属性
QGroupBox 实现一个带有标题的分组框,可以把其他的控件放到里面称为一组,这个分组框也没有什么强大的功能,只是让界面看起来好看一些,主要属性如下:
属性 | 说明 |
---|---|
title | 分组框的标题 |
alignment | 分组框内部内容的对齐方式 |
flat | 是否是"扁平"模式 |
checkable | 是否可选择 设为 true 则在title前方会多出一个可勾选的部分 |
checked | 描述分组框的选择状态(前提是checkable为true) |
2.2 点餐系统再升级

然后内部的逻辑我们就不实现了,因为和前面的是一样的:QT跨平台应用程序开发框架(7)------ 常用输入类控件-CSDN博客
三,Tab Widget
3.1 主要属性
QTabWidget 表示一个带有标签页的控件,可以在里面添加一些 widget,可以通过标签页来切换,可以类比下浏览器上方的标签页,主要属性如下:
属性 | 说明 |
---|---|
tabPosition | 标签⻚所在的位置 * North:上方 * South:下方 * West:左侧 * East:右侧 |
currentIndex | 当前选中了第几个标签页(从0开始计算) |
currentTabText | 当前选中的标签页的文本 |
currentTabName | 当前选中的标签页的名字 |
currentTabIcon | 当前选中的标签页的图标 |
currentTabToolTip | 当前选中的标签页的提示信息 |
tabsCloseable | 标签页是否可以关闭 |
movable | 标签页是否可以移动 |
主要信号如下:
信号 | 说明 |
---|---|
currentChanged(int) | 在标签页发生切换时触发,参数为被点击的选项卡编号 |
tabBarClicked(int) | 在点击选项卡的标签条的时候触发,参数为被点击的选项卡编号 |
tabBarDoubleClicked(int) | 在双击选项卡的标签条的时候触发,参数为被点击的选项卡编号 |
tabCloseRequest(int) | 在标签页关闭时触发,参数为被关闭的选项卡编号 |
3.2 代码示例
我们下面实现的程序期望是:
- 创建一个程序,带有一个 TableWidget 作为标签页
- 提供两个按钮,分别创建新的标签页,关闭当前选中的标签页
- 当切换标签页时,也能感知到变化
先创建下列控件:

代码如下:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//先在每个标签页添加一个 label
QLabel* l1 = new QLabel(ui->tab);
l1->setText("标签页1");
l1->resize(100, 50);
QLabel* l2 = new QLabel(ui->tab_2);
l2->setText("标签页2");
l2->resize(100, 50);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QWidget* w = new QWidget();
int count = ui->tabWidget->count(); //获取当前标签页数量,新增时 + 1
ui->tabWidget->addTab(w, QString("Tab ") + QString::number(count + 1));
//addTab表示创建新的标签页,第一个参数表示要添加的控件,第二个参数表示新增标签页的标题
//也可以添加一个输入框,让用户输入标签页标题
QLabel* label = new QLabel(w);
label->setText(QString("标签页 ") + QString::number(count + 1));
label->resize(100, 50);
ui->tabWidget->setCurrentIndex(count + 1); //设置选中新标签页
}
void Widget::on_pushButton_2_clicked()
{
int index = ui->tabWidget->currentIndex(); //获取当前选中标签页的下标
ui->tabWidget->removeTab(index); //删除标签页
}
void Widget::on_tabWidget_currentChanged(int index)
{
//当标签页切换时,触发此信号
}
效果如下:

四,布局管理器
4.1 垂直布局
问题:为什么要有布局管理器?
解答:我们前面使用ui创建界面时,都是手动拖拽方式来布局的,其实这种方式不科学
- 手动布局方式很复杂,而且不精确
- 无法对窗口大小进行自适应
所以需要布局管理器使控件的布局更加灵活,有四种
QVBoxLayout 表示垂直布局管理器,V 是 vertical 的缩写,主要属性如下:
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
下面是布局管理器的基本用法:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//先创建三个按钮,然后使用布局管理器管理起来
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
QPushButton* b3 = new QPushButton("按钮3");
//创建布局管理器对象
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(b1);
layout->addWidget(b2);
layout->addWidget(b3);
//把布局管理器添加到窗口中
this->setLayout(layout); //
}
效果如下:

每个 Widget 只能设置一个布局管理器, 但是可以通过拖拽方式创建两个布局遍历器,但是这样创建的布局管理器仅仅只会将内部控件重新组合位置,并不会像上面一样随着窗口大小改变
因为在 Qt Designer 中创建的 layout,是先创建了一个 Widget,然后再在这个新的 Widget 中添加了一个 layout
4.2 水平布局
QHBoxLayout 表示水平的布局管理器,H 是 horizontal 的缩写,核心属性和垂直布局管理器一致:
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
而且在使用上也和垂直布局管理器一样的,下面简单演示一下:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//先创建三个按钮,然后使用布局管理器管理起来
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
QPushButton* b3 = new QPushButton("按钮3");
//创建水平布局管理器对象
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(b1);
layout->addWidget(b2);
layout->addWidget(b3);
//把布局管理器添加到窗口中
this->setLayout(layout); //
}

布局管理器之间也能进行嵌套,如下代码:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QVBoxLayout* vlayout = new QVBoxLayout(); //垂直布局管理器
this->setLayout(vlayout);
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
vlayout->addWidget(b1);
vlayout->addWidget(b2);
QHBoxLayout* hlayout = new QHBoxLayout(); //水平布局管理器
QPushButton* b3 = new QPushButton("按钮3");
QPushButton* b4 = new QPushButton("按钮4");
hlayout->addWidget(b3);
hlayout->addWidget(b4);
vlayout->addLayout(hlayout);
}
效果如下:

4.3 网格布局
QGridLayout 用来实现网格布局的效果,可以达到 M * N 的这种网格效果,主要属性和 QHBoxLayout 类似,但是设置 spacing 的时候是按照垂直水平两个方向来设置的
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutHorizontalSpacing | 相邻元素之间水平方向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直方向的间距 |
layoutRowStretch | 行方向的拉伸系数 |
layoutColumnStretch | 列方向的拉伸系数 |
如下代码:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
QPushButton* b3 = new QPushButton("按钮3");
QPushButton* b4 = new QPushButton("按钮4");
QGridLayout* layout = new QGridLayout();
// layout->addWidget(b1, 0, 0); //需要指定行和列
// layout->addWidget(b2, 0, 1); //第 0 行,第 1 列
// layout->addWidget(b3, 1, 0);
// layout->addWidget(b4, 1, 1);
//我们还可以更灵活的指定按钮的位置,如下:
layout->addWidget(b1, 0, 0); //需要指定行和列
layout->addWidget(b2, 1, 1); //第 0 行,第 1 列
layout->addWidget(b3, 2, 2);
layout->addWidget(b4, 3, 3);
this->setLayout(layout);
}

当列号相同时,效果相当于水平布局;当行号相同时,相当于垂直布局了
4.4 拉伸系数
- 我们上面创建的布局管理器中的控件的各种属性,比如宽度高度等间距等都是一样的
- 此时当我们需要创建出不同尺寸的控件时,可以通过拉伸系数来设置
- 拉伸系数相当于控件之前尺寸的比例
下面是演示拉伸系数代码演示:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建 9 个按钮,使用网格布局按照3 * 3 的方式排列
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
QPushButton* b3 = new QPushButton("按钮3");
QPushButton* b4 = new QPushButton("按钮4");
QPushButton* b5 = new QPushButton("按钮5");
QPushButton* b6 = new QPushButton("按钮6");
QPushButton* b7 = new QPushButton("按钮7");
QPushButton* b8 = new QPushButton("按钮8");
QPushButton* b9 = new QPushButton("按钮9");
QGridLayout* layout = new QGridLayout();
layout->addWidget(b1, 0, 0);
layout->addWidget(b2, 0, 1);
layout->addWidget(b3, 0, 2);
layout->addWidget(b4, 1, 0);
layout->addWidget(b5, 1, 1);
layout->addWidget(b6, 1, 2);
layout->addWidget(b7, 2, 0);
layout->addWidget(b8, 2, 1);
layout->addWidget(b9, 2, 2);
this->setLayout(layout);
//设置水平拉伸系数,期望是让每一列的尺寸都不一样
//设置列方向拉伸系数,第一个参数是列数,第二个是拉伸的系数
layout->setColumnStretch(0, 0); //如果拉伸系数设为0,则表示不参与拉伸,此时按钮宽度是固定值
layout->setColumnStretch(1, 1);
layout->setColumnStretch(2, 2);
//设置垂直拉伸系数,QGridLayout 也提供了 setRowStretch 设置行之间的拉伸系数
//但是直接设置没有效果,是因为 SizePolicy 的影响
//由于按钮的垂直方向默认没有拉伸开,而水平方向默认是拉伸开的
//所以需要把按钮的 sizePolicy 属性设置为 QSizePolicy::Expanding 才行
b1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //表示让按钮的垂直和水平都拉伸开
b2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
b3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
b4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
b5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
b6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
b7->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
b8->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
b9->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//正式设置拉伸系数
layout->setRowStretch(0, 0);
layout->setRowStretch(1, 1);
layout->setRowStretch(2, 2);
}
效果如下:

4.5 表单布局
QFormLayout 是 QGridLayout 的特殊情况,专门用于实现两列表单的布局,比如让用户填写信息的常见,左侧为文字提示,右侧为输入框,如下代码:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 layout
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
// 创建三个 layout
QLabel* label1 = new QLabel("姓名");
QLabel* label2 = new QLabel("年龄");
QLabel* label3 = new QLabel("电话");
// 创建三个 lineEdit
QLineEdit* lineEdit1 = new QLineEdit();
QLineEdit* lineEdit2 = new QLineEdit();
QLineEdit* lineEdit3 = new QLineEdit();
// 创建⼀个提交按钮
QPushButton* btn = new QPushButton("提交");
// 把上述元素添加到 layout 中
layout->addRow(label1, lineEdit1);
layout->addRow(label2, lineEdit2);
layout->addRow(label3, lineEdit3);
layout->addRow(NULL, btn);
}

五,Spacer
使用布局管理器时,可能需要在控件之间添加一段空白,就可以使用 QSpacerItem 来表示
主要属性:
属性 | 说明 |
---|---|
width | 宽度 |
height | 高度 |
dData | 水平方向的sizePolicy * QSizePolicy::Ignored:忽略控件的尺寸,不对布局产生影响 * QSizePolicy::Minimum :控件的最小尺寸为固定值,布局时不会超过该值 * QSizePolicy::Maximum:控件的最大尺存为固定值,布局时不会小于该值。 * QSizePolicy::Preferred:控件的理想尺寸为固定值,布局时会尽量接近该值 * QSizePolicy::Expanding:控件的尺寸可以根据空间调整,尽可能占据更多空间 * QSizePolicy::Shrinking:控件的尺寸可以根据空间调整,尽可能缩小以适应空间 |
vData | 垂直防线的 sizePolicy,选项同上 |
假设我们使用垂直布局创建两个按钮,但是直接创建的话两个按钮是挨在一起的,我们想让两个按钮中间隔开些距离,代码如下:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QHBoxLayout* layout = new QHBoxLayout();
this->setLayout(layout);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
// 创建Spacer
QSpacerItem* spacer = new QSpacerItem(200, 20);
layout->addWidget(btn1);
//在两个按钮中间添加空⽩
layout->addSpacerItem(spacer); //放在哪里就在哪里添加空白,比如放到上面按钮前面,就是在前面添加空白
layout->addWidget(btn2);
}
