【Qt】常用控件----容器类控件(QGroupBox、QTabWidget )以及布局管理器

目录

前言

书接上文【Qt】常用控件----多元素控件(QListWidget、QTableWidget、QTreeWidget),今天继续介绍【Qt】常用控件----容器类控件(QGroupBox、QTabWidget )以及布局管理器

一、多元素控件和容器类控件区别

  • 多元素控件:包含的内容是一个一个自定义好的"Item"对象
  • 容器类控件:包含的内容是前面我们学习的各种控件(QPushButton、QLineEdit等)

二、容器类控件

1、Group Box

  • 使用QGroupBox 实现一个带有标题的分组框。可以把其他的控件放到里面作为⼀组,这样看起来能更好看一点
  • 分组框只是一个用来美化界面 这样的组件,并不涉及到用户交互和业务逻辑。属于"锦上添花"

核心属性

属性 说明
title 分组框的标题
alignment 分组框内部内容的对齐方式
flat 是否是"扁平"模式
checkable 是否可选择。设为true则在title前方会多出一个可勾选的部分
checked 描述分组框的选择状态(前提是checkable为true)

给麦当劳案例加上分组框

  • 在界面上创建三个分组框,并且在分组框内部创建下拉框和微调框
  • 初始化下拉框
cpp 复制代码
    ui->comboBox->addItem("巨⽆霸");
    ui->comboBox->addItem("⻨辣鸡腿堡");

    ui->comboBox_2->addItem("薯条");
    ui->comboBox_2->addItem("⻨辣鸡翅");

    ui->comboBox_3->addItem("可乐");
    ui->comboBox_3->addItem("雪碧");

2、Tab Widget

  • 使用QTabWidget 实现一个带有标签页的控件,可以往里面添加一些widget。进一步的就可以通过标签页来切换
  • QTabWidget 中的每个标签页都是一个QWidget
  • 如果想要插入标签页,可以右键->插入页

  • 删除页:右键->3的页3->删除

核心属性

属性 说明
tabPosition 标签页所在的位置:North 上方;South 下方;West 左侧;East 右侧
currentIndex 当前选中了第几个标签页(从0开始计算)
currentTabText 当前选中的标签页的文本
currentTabName 当前选中的标签页的名字
currentTabIcon 当前选中的标签页的图标
currentTabToolTip 当前选中的标签页的提示信息
tabsCloseable 标签页是否可以关闭
movable 标签页是否可以移动

核心信号

信号 说明
currentChanged(int) 在标签页发生切换时触发,参数为被点击的选项卡编号
tabBarClicked(int) 在点击选项卡的标签条的时候触发。参数为被点击的选项卡编号
tabBarDoubleClicked(int) 在双击选项卡的标签条的时候触发。参数为被点击的选项卡编号
tabCloseRequest(int) 在标签页关闭时触发。参数为被关闭的选项卡编号

使用标签页管理多组控件

  • 创建一个QTabWidget标签页和两个按钮(分别是新建标签页按钮和删除当前标签页按钮)。
  • 给标签页中添加一个label
cpp 复制代码
    //添加标签
    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函数
  1. 首先获取标签页个数
  2. 使用addTab 新增标签页(参数1:QWidget对象,参数2:标签页页名。同时在标签页中添加label标签,使用setCurrentIndex 切换当前标签页)
  3. 使用removeTab 删除标签页:使用currentIndex 获取到当前标签页的下标
cpp 复制代码
void Widget::on_pushButton_clicked()
{
    //插入标签页使用addTab
    //参数1 QWidget
    //参数2 标签页名text,Tab + 数字
    int count = ui->tabWidget->count();
    QWidget* widget = new QWidget();
    ui->tabWidget->addTab(widget, QString("Tab") + QString::number(count + 1));

    //添加QLabel
    QLabel* label = new QLabel(widget);
    label->setText("标签" + QString::number(count + 1));
    label->resize(100, 50);
    
    //设置新增标签页被选中
    ui->tabWidget->setCurrentIndex(count);
}

void Widget::on_pushButton_2_clicked()
{
    //获取选中标签页下标
    int index = ui->tabWidget->currentIndex();
    //删除
    ui->tabWidget->removeTab(index);
    
}

三、布局管理器

  • 之前使用Qt在界面上创建的控件,都是通过"绝对定位"的方式来设定的。也就是每个控件所在的位置,都需要计算坐标,最终通过setGeometry 或者move 方式摆放过去
  • 这种设定方式其实并不方便。尤其是界面如果内容比较多,不好计算。而且一个窗口大小往往是可以调整的,按照绝对定位的方式,也无法自适应窗口大小
  • 因此Qt引入"布局管理器"(Layout)机制来解决上述问题

1、垂直布局(QVBoxLayout)

  • 使用QVBoxLayout 表示垂直的布局管理器。V是vertical的缩写

核心属性

属性 说明
layoutLeftMargin 左侧边距
layoutRightMargin 右侧边距
layoutTopMargin 上方边距
layoutBottomMargin 下方边距
layoutSpacing 相邻元素之间的间距
  • Layout只是用于界面布局,并没有提供信号

使用QVBoxLayout 管理多个控件

  • 编写代码创建布局管理器和三个按钮,并且把按钮添加到布局管理器中
  1. 使用addWidget 把控件添加到布局管理器中
  2. 使用setLayout 设置该布局管理器到widget中
  3. 下面代码我们可以发现在创建button1和layout 的时候,我们没有直接指定其父元素,后面我们使用addWidget 和setLayout 就是在将其挂在对象树上
cpp 复制代码
    //创建3个按钮,使用垂直布局管理器管理起来
    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);
  1. 通过上述代码的方式,只能给这个widget设定一个布局管理器。实际上也可以通过Qt Design在一个窗口中创建多个布局管理器

窗口中创建多个布局管理器(创建两个QVBoxLayout)

  • 在界面上创建两个QVBoxLayout ,每个QVBoxLayout 各放三个按钮
  • 运行程序可以看到这些按钮已经自动排列好。只不过当前这些按钮的位置不能随着窗口大小自动变化
  • 通过Qt Designer创建的布局管理器,其实是先创建了一个widget,设置过geometry属性的。再把这个layout设置到这个widget中
  • 实际上一个widget只能包含一个layout
  • 打开ui文件的原始xml,可以看到其中的端倪

2、水平布局(QHBoxLayout)

  • 使用QHBoxLayout 表示垂直的布局管理器。H是horizontal 的缩写

核心属性(和QVBoxLayout完全一样)

属性 说明
layoutLeftMargin 左侧边距
layoutRightMargin 右侧边距
layoutTopMargin 上方边距
layoutBottomMargin 下方边距
layoutSpacing 相邻元素之间的间距

使用QHBoxLayout管理控件

  • 编写代码创建布局管理器和三个按钮,并且把按钮添加到布局管理器中(和QVBoxLayout操作完全一样)
cpp 复制代码
    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 复制代码
    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");

    //父layout
    QVBoxLayout* layParent = new QVBoxLayout();
    layParent->addWidget(button1);
    layParent->addWidget(button2);
    this->setLayout(layParent);

    QPushButton* button3 = new QPushButton("按钮3");
    QPushButton* button4 = new QPushButton("按钮4");

    //子layout
    QHBoxLayout* layChild = new QHBoxLayout();
    layChild->addWidget(button3);
    layChild->addWidget(button4);

    layParent->addLayout(layChild);

3、网格布局(QGridLayout)

Qt中还提供了QGridLayout 用来实现网格布局的效果。可以达到M*N的这种网格的效果

核心属性

  • 整体和QVBoxLayout 以及QHBoxLayout 相似。但是设置spacing的时候是按照垂直水平两个方向来设置的
属性 说明
layoutLeftMargin 左侧边距
layoutRightMargin 右侧边距
layoutTopMargin 上方边距
layoutBottomMargin 下方边距
layoutHorizontalSpacing 相邻元素之间水平方向的间距
layoutVerticalSpacing 相邻元素之间垂直方向的间距
layoutRowStretch 行方向的拉伸系数
layoutColumnStretch 列方向的拉伸系数

使用QGridLayout管理元素

  • 代码中创建QGridLayout 和4个按钮
  • 使用addWidget添加控件到布局管理器中,但是添加的同时会指定两个坐标,表示放在第几行第几列
cpp 复制代码
    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);

    this->setLayout(layout);
  • 当QGridLayout的addWidget中的行是一样的,就相当于QHBoxLayout;列相同就相当于QVBoxLayout
  • 此处也要注意,设置行和列的时候,如果设置的是一个很大的值,但是这个值和上一个值之间并没有其他的元素,那么并不会在中间腾出额外的空间

设置QGridLayout中元素的大小比例

  • 上面我们创建的布局管理器的控件尺寸都是均等的
  • 当我们需要创建尺寸不同的控件的时候,就可以通过拉伸系数来设置。拉伸系数就相当于设置控件之间尺寸的"比例"
水平拉伸系数
  • 创建6个按钮,按照2行3列的方式排列
cpp 复制代码
    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮3");
    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);

    this->setLayout(layout);
  • 设置水平拉伸系数
  • 下面代码的含义:三列按照1:1:2的方式来设置
  • 如果拉伸系数设为0,意思是不参与拉伸,尺寸是固定值
cpp 复制代码
    //设置水平拉伸系数
    layout->setColumnStretch(0, 1);
    layout->setColumnStretch(1, 1);
    layout->setColumnStretch(2, 2);
垂直拉伸系数
  • 创建6个按钮,按照3行2列的方式排列
cpp 复制代码
    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, 1, 0);
    layout->addWidget(button4, 1, 1);
    layout->addWidget(button5, 2, 0);
    layout->addWidget(button6, 2, 1);

    this->setLayout(layout);
  • 设置垂直拉伸系数
  1. 直接设置setRowStretch 效果不明显。因为每个按钮的高度是固定的(垂直方向默认是没有拉伸的,水平方向默认是拉伸的)。需要把按钮的垂直方向的sizePolicy
    属性设置为QSizePolicy::Expanding 尽可能填充满布局管理器,才能看到效果

使用setSizePolicy 设置按钮的尺寸策略,可选的值如下:

  • QSizePolicy::Ignored :忽略控件的尺寸,不对布局产生影响
  • QSizePolicy::Minimum :控件的最小尺寸为固定值,布局时不会超过该值
  • QSizePolicy::Maximum :控件的最大尺寸为固定值,布局时不会小于该值
  • QSizePolicy::Preferred :控件的理想尺寸为固定值,布局时会尽量接近该值
  • QSizePolicy::Expanding :控件的尺寸可以根据空间调整,尽可能占据更多空间
  • QSizePolicy::Shrinking :控件的尺寸可以根据空间调整,尽可能缩小以适应空间
cpp 复制代码
    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);
  1. 设置垂直拉伸系数
cpp 复制代码
    //设置垂直拉伸系数
    layout->setRowStretch(0, 1);
    layout->setRowStretch(1, 1);
    layout->setRowStretch(2, 2);
  • 总的来说,使用QGridLayout 能够代替很多QHBoxLayout 和QVBoxLayout 嵌套的场景

4、表单布局(QFormLayout)

  • 除了上述的布局管理器之外,Qt还提供了QFormLayout ,属于是QGridLayout 的特殊情况,专们用于实现两列表单的布局
  • 这种表单布局多用于让用户填写信息的场景(填表、调查问卷)。左侧列为提示,右侧列为输入框

使用QFormLayout创建表单

  • 编写代码创建QFormLayout 以及三个label和三个lineEdit,一个提交按钮控件
  • 使用addRow方法来添加一行。每行包含两个控件:第⼀个控件固定是QLabel/文本,第二个控件则可以是任意控件
cpp 复制代码
    QFormLayout* layout = new QFormLayout();
    this->setLayout(layout);
    
    QLabel* label1 = new QLabel("姓名");
    QLabel* label2 = new QLabel("年龄");
    QLabel* label3 = new QLabel("电话");

    QLineEdit* edit1 = new QLineEdit();
    QLineEdit* edit2 = new QLineEdit();
    QLineEdit* edit3 = new QLineEdit();

    QPushButton* button = new QPushButton("提交");

    //上述控件添加到表单中
    layout->addRow(label1, edit1);
    layout->addRow(label2, edit2);
    layout->addRow(label3, edit3);
    layout->addRow(nullptr, button);

5、Spacer(QSpacerItem)

使用布局管理器的时候,可能需要在控件之间添加⼀段空白,就可以用QSpacerItem 来表示

核心属性(在构造函数设置即可)

属性 说明
width 宽度
height 高度
hData 水平方向的sizePolicyQSizePolicy::Ignored :忽略控件的尺寸,不对布局产生影响;QSizePolicy::Minimum:控件的最小尺寸为固定值,布局时不会超过该值;QSizePolicy::Maximum :控件的最大尺寸为固定值,布局时不会小于该值;QSizePolicy::Preferred :控件的理想尺寸为固定值,布局时会尽量接近该值;QSizePolicy::Expanding :控件的尺寸可以根据空间调整,尽可能占据更多空间;QSizePolicy::Shrinking:控件的尺寸可以根据空间调整,尽可能缩小以适应空间
vData 垂直方向的sizePolicy(选项同上)

创建一组左右排列的按钮

  • 在界面上创建一个QHBoxLayout ,并添加两个按钮
cpp 复制代码
    QHBoxLayout* layout = new QHBoxLayout();
    this->setLayout(layout);

    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");
    layout->addWidget(button1);
    layout->addWidget(button2);
}
  • 上面两个水平排列的按钮之间距离很近,使用QSpacerItem使两个按钮之间存在空白
  • layout->addSpacerItem(spacer)代码位置会影响添加空白的位置,现在我们需要在两个按钮之间,因此在两个按钮之间添加到layout上,如果是在button1前面添加,则要在button1添加到layout管理布局器之前添加
cpp 复制代码
    //创建spacer,使两个按钮之间存在空白
    QSpacerItem* spacer = new QSpacerItem(200, 20);
    layout->addWidget(button1);
    layout->addSpacerItem(spacer);
    layout->addWidget(button2);
  • 在Qt Designer中,也可以直接给界面上添加spacer
相关推荐
pulinzt2 分钟前
【python第三节】循环+函数初步
开发语言·python
zfj3212 分钟前
java垃圾收集 minorgc majargc fullgc
java·开发语言·jvm·gc·垃圾收集器
skywalk816312 分钟前
Auto-Coder常用秘籍 autocoder.chat启动之后的处理
开发语言·人工智能
叠叠乐13 分钟前
bash sh为什么终端不能tab补全
开发语言·bash
superman超哥22 分钟前
Rust Rc与Arc的引用计数机制:共享所有权的两种实现
开发语言·后端·rust·编程语言·rust rc与arc·引用计数机制·共享所有权
提笔忘字的帝国24 分钟前
【2026版】macOS 使用 Homebrew 快速安装 Java 21 教程
java·开发语言·macos
半壶清水24 分钟前
【开源免费】使用 Python + Whisper + PyDub 自动切割长音频文件
开发语言·python·语言模型·开源·whisper
ghostwritten25 分钟前
go.mod 与go.sum有什么区别?
开发语言·后端·golang
抹香鲸之海30 分钟前
Easyexcel 多级横向合并表头
java·开发语言·windows
环黄金线HHJX.31 分钟前
【MCP: Tuan编程 + Qt架构 + QoS - 量子-经典混合计算管理控制平台】
ide·人工智能·qt·编辑器·量子计算