每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry”
🤔绪论:
在Qt开发中,界面布局的合理设计是提升用户体验的关键。早期,开发者常采用绝对定位的方式摆放控件,即通过计算坐标并使用setGeometry或move方法逐一定位。然而,这种方法不仅复杂且不精确,难以适应窗口大小的变化,尤其在界面内容繁杂时,计算难度显著增加。
为解决这一问题,Qt引入了布局管理器机制,通过QVBoxLayout(垂直布局)、QHBoxLayout(水平布局)、QGridLayout(网格布局)和QFormLayout(表单布局)等工具,实现了控件的自动排列与窗口大小的自适应调整。布局管理器不仅简化了界面设计流程,还提高了布局的灵活性和可维护性,成为Qt开发中不可或缺的一部分。本文将详细介绍这些布局管理器的使用方法与技巧,助力开发者高效构建Qt界面。
————————
早关注不迷路🎠,话不多说安全带系好,发车啦(建议电脑🖥️观看)。
🐱🐉布局管理器
之前使⽤ Qt 在界⾯上创建的控件, 都是通过 “绝对定位” 的⽅式来设定的。也就是每个控件所在的位置, 都需要计算坐标, 最终通过 setGeometry 或者 move ⽅式摆放过去。这种方式虽然不错,但这种设定⽅式其实并不⽅便
- 手动布局非常复杂,而且不精确、并且无法对窗口的大小自适应
- 尤其是界⾯如果内容⽐较多, 不好计算
- ⽽且⼀个窗⼝⼤⼩往往是可以调整的, 按照绝对定位的⽅式, 也⽆法⾃适应窗⼝⼤⼩。
- 因此 Qt 引⼊ “布局管理器” (Layout) 机制, 来解决上述问题.
当然,布局管理器并非 Qt 独有。其他的 GUI 开发框架,像 Android,前端等也有类似的机制。
Qt中提供了很多种布局管理器
- 垂直布局
- 水平布局
- 网格布局(行列)
- 表单布局
⛰️垂直布局 QVBoxLayout
使⽤ QVBoxLayout 表⽰垂直的布局管理器(V 就是 vertical 的缩写)
核⼼属性🎈
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutSpacing | 相邻元素之间的间距 |
实操1📄
- 目的:创建3个按钮,使用垂直布局管理器管理起来
- 创建三个按钮通过构造填写文本(布局管理器作为父元素,后续只需通过该布局管理器进行添加操作即可)
- 创建布局管理器对象
- 将三个按钮添加布局管理器中(
addWidget
)这样三个按钮以及布局管理都是在对象树上的 - 将布局管理器设置到窗口上(
setLayout
)
#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* 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::~Widget()
{
delete ui;
}
此时拖拽窗口,按钮就会自适应窗口
更多细节🔥
-
注意:在代码中,当你调用QWidget::setLayout()时,只能设置一个布局管理器,但允许嵌套多个布局管理器。这个布局管理器会成为Widget的直接布局管理器。
-
在代码中创建多个layout时,它们会嵌套在第一个生成的Layout上。
- layout 标签表示的是布局管理器的本体,外面会自动创建出了一个Widget
- 每个layout里面就可以包含若干个item(也就是如按钮的控件)
-
也可以先拖拽其他控件,然后再套上layout
-
框选住刚刚拖拽的控件,然后点击再左上角(如下图)就能放到layout中
水🌊平布局 QHBoxLayout
使⽤ QHBoxLayout 表⽰垂直的布局管理器(H 是 horizontal 的缩写)
核⼼属性 🎈
(和 QVBoxLayout 属性是⼀致的)
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutSpacing | 相邻元素之间的间距 |
实操1📄
- 创建出三个按钮,按钮1/2/3
- 创建QHBoxLayout对象
- 将按钮添加到layout中(addWidget)
- 再将layout设置到this上(setLayout)
- 还能通过layoutLeftMargin…等设置边距
#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* 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);
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
QPushButton* b3 = new QPushButton("按钮3");
//创建一个v布局管理器
QHBoxLayout* layout = new QHBoxLayout();
//将按钮添加到布局管理器中
layout->addWidget(b1);
layout->addWidget(b2);
layout->addWidget(b3);
setLayout(layout);
layout->setMargin(200);//边距
layout->setSpacing(50);//内部控件见的距离
}
Widget::~Widget()
{
delete ui;
}
实操2 🗒️
布局管理器之间,也能嵌套布局管理器(如下图:垂直布局内部嵌套水平布局):
- 创建垂直布局管理器 QVBoxLayout对象
- 设置到窗口里面:setLayout
- 添加两个按钮进去addWidget
- 创建一个水平的布局管理
- 也添加两个按钮进去
- 把水平布局管理器添加到垂直布局管理器内部(addLayout)
#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* b1 = new QPushButton("按钮1");
// QPushButton* b2 = new QPushButton("按钮2");
// QPushButton* b3 = new QPushButton("按钮3");
QVBoxLayout* vLayout = new QVBoxLayout();
this->setLayout(vLayout);
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
//创建一个v布局管理器
QHBoxLayout* hLayout = new QHBoxLayout();
//将按钮添加到布局管理器中
hLayout->addWidget(b1);
hLayout->addWidget(b2);
QPushButton* b4 = new QPushButton("按钮4");
QPushButton* b5 = new QPushButton("按钮5");
vLayout->addWidget(b4);
vLayout->addWidget(b5);
vLayout->addLayout(hLayout);
}
Widget::~Widget()
{
delete ui;
}
🏁⽹格布局 QGridLayout
Qt 中还提供了 QGridLayout ⽤来实现⽹格布局的效果。可以达到 M * N 的这种⽹格的效果
核⼼属性🎈
整体和 QVBoxLayout 以及 QHBoxLayout 相似. 但是设置 spacing 的时候是按照垂直⽔平两个⽅向来设置的
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutHorizontalSpacing | 相邻元素之间⽔平⽅向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直⽅向的间距 |
layoutRowStretch | ⾏⽅向的拉伸系数 |
layoutColumnStretch | 列⽅向的拉伸系数 |
实操1 🗒️
-
创建4个按钮 按钮1/2/3/4
-
创建一个QGridLayout网格布局对象
-
添加将按钮添加进去
addWidget
,其中传递过程中还需要设置 行、列 -
将网格布局管理器设置到窗口中
setLayout
-
因为是行列的添加按钮的位置,所以可以随意的放到网格中
-
将4个按钮都放到同一行(就相当于水平布局)
-
同理放到同一列(就相当于垂直布局)
-
甚至也还可以斜着布局
-
-
任意调整⾏列, 即可看到不同的效果 ,但注意的是如果设置的是⼀个很⼤的值, 但是这个值和上⼀个值之间并没有其他的元素,那么并不会在中间腾出额外的空间
-
此处设置的行数和列数,只是用来决定控件之间的相对位置,谁先谁后
#include "widget.h"
#include "ui_widget.h"
#include <QGridLayout>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建GridLayout布局管理器
QGridLayout* grid = new QGridLayout();
//创建4按按钮
QPushButton* b1 = new QPushButton("按钮1");
QPushButton* b2 = new QPushButton("按钮2");
QPushButton* b3 = new QPushButton("按钮3");
QPushButton* b4 = new QPushButton("按钮4");
//水平布局
// grid->addWidget(b1,0,0);
// grid->addWidget(b2,0,1);
// grid->addWidget(b3,0,2);
// grid->addWidget(b4,0,3);
// //垂直布局
// grid->addWidget(b1,0,0);
// grid->addWidget(b2,1,0);
// grid->addWidget(b3,2,0);
// grid->addWidget(b4,3,0);
//斜着布局
grid->addWidget(b1,0,0);
grid->addWidget(b2,1,1);
grid->addWidget(b3,2,2);
grid->addWidget(b4,3,300);
setLayout(grid);
}
Widget::~Widget()
{
delete ui;
}
了解下拉伸系数🍜:
- 刚刚创建的布局管理器,里面控件的尺寸都是均等的
- 当需要创建出尺寸不同的是,就可以设置拉伸系数
- 拉伸系数就相当于设置控件之间尺寸的比例
实操:
- 创建 6个 按钮1 ~ 6,使用网格布局 2 * 3 的方式排列(ui拖拽)
在设置水平拉伸系数 setColumnStretch
:按照1:1:2的比例进行放置
当拉伸系数设为设为0,就不参与拉伸,那么按钮的大小就是固定值
设置垂直⛰️拉伸系数的问题
当我们设置垂直拉伸系数,发现其实并没有效果
这是因为QSizePolicy
的限制(默认是Ignored的):
- QSizePolicy::Ignored : 忽略控件的尺⼨,不对布局产⽣影响
- QSizePolicy::Minimum : 控件的最⼩尺⼨为固定值,布局时不会超过该值。
- QSizePolicy::Maximum : 控件的最⼤尺⼨为固定值,布局时不会⼩于该值。
- QSizePolicy::Preferred : 控件的理想尺⼨为固定值,布局时会尽量接近该值。
- QSizePolicy::Expanding : 控件的尺⼨可以根据空间调整,尽可能占据更多空间。
- QSizePolicy::Shrinking : 控件的尺⼨可以根据空间调整,尽可能缩⼩以适应空间
- 所以按钮设置 setSizePolicy 的尺⼨策略为 QSizePolicy::Expanding,让其可以拉伸展开(需要同时设置垂直和水平)
这样就能完成垂直的策略
//将三列中比例为 1:1:3
ui->gridLayout->setColumnStretch(0,1);
ui->gridLayout->setColumnStretch(1,1);
ui->gridLayout->setColumnStretch(2,3);
//将行的比例为 1:3
ui->gridLayout->setRowStretch(0,1);
ui->gridLayout->setRowStretch(1,3);
//设置策略
ui->pushButton->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);//将行列的延展设置为自动扩展
ui->pushButton_2->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);//将行列的延展设置为自动扩展
ui->pushButton_3->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);//将行列的延展设置为自动扩展
ui->pushButton_4->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);//将行列的延展设置为自动扩展
ui->pushButton_5->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);//将行列的延展设置为自动扩展
ui->pushButton_6->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);//将行列的延展设置为自动扩展
表⌚单布局 QFormLayout
类似一种填表,填调查问卷的样式,一般是 N 行 2 列
直接上实操:
- 设置3行2列的表单,并设置到窗口中
- 创建3个label,并作为第一列
- 创建3个输入框作为第二列
- 将上述控件添加到表单中
addRow(Column1,Column2,...)
(添加到行中) - 创建一个提交按钮,并同样放到表单中
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QLineEdit>
#include <QFormLayout>
#include <QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 layout
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
// 创建三个 label
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);
}
Widget::~Widget()
{
delete ui;
}
Spacer 空⽩🐏
使⽤布局管理器的时候, 可能需要在控件之间, 添加⼀段空⽩
- 就可以使⽤ QSpacerItem 来表⽰,通过添加这个控件来达到空白的效果
核⼼属性🎈:
属性 | 说明 |
---|---|
width | 宽度 |
height | ⾼度 |
hData | ⽔平⽅向的 sizePolicy • QSizePolicy::Ignored : 忽略控件的尺⼨,不对布局产⽣影响。 • QSizePolicy::Minimum : 控件的最⼩尺⼨为固定值,布局时不会超过该值。 • QSizePolicy::Maximum : 控件的最⼤尺⼨为固定值,布局时不会⼩于该值。 • QSizePolicy::Preferred : 控件的理想尺⼨为固定值,布局时会尽量接近该值。 • QSizePolicy::Expanding : 控件的尺⼨可以根据空间调整,尽可能占据更多空间。 • QSizePolicy::Shrinking : 控件的尺⼨可以根据空间调整,尽可能缩⼩以适应空间。 |
vData | 垂直⽅向的 sizePolicy 选项同上 |
实操 让两个按钮中间有一定的空白
- 创建QHBoxLayout,并设置到创建中
- 创建两个按钮,并添加到水平布局中
默认情况如下: - 图按钮中间并没有空隙,现在想要让他空开一点:
- 就可以使用 spacer 使两个按钮之间存在空白
- 通过
addSpacerItem
进行添加 spacer 控件
- QSpacerItem构造的的时候设置宽高
- 通过添加空间的顺序确定spacer的位置
若放到前面则:
当然在ui文件中也是有的:
小总结🪢:
前面的每个控件本质都是可扩展的,每个控件都是Qt内置的一个类,咱们在代码中都可以基于这个类,继承出自定义的子类,在这个自定义的子类中,又可以添加许多的属性和方法,实现自己的需求场景,还可以在子类中,把多个控价组合到一起
本章完。预知后事如何,暂听下回分解。
如果有任何问题欢迎讨论哈!
如果觉得这篇文章对你有所帮助的话点点赞吧!
持续更新大量C++ Qt细致内容,早关注不迷路。