【Qt】布局管理器

界面中各元素排列有序往往会更加的美观,Qt Designer虽然通过拖拽的方式添加控件简便了开发,但手动界面编排还是较为麻烦,为此Qt提供了布局管理器

布局管理器用于管理和安排窗口控件(widgets),帮助确保界面在不同平台和窗口尺寸下保持一致和合理的布局。布局管理器负责调整和定位窗口部件,以便它们在窗口大小变化时能适应不同的布局需求

QBoxLayout

QBoxLayout 是矩形布局管理器,其管理的界面范围是一个矩形。Qt将其封装,形成了QVBoxLayout (垂直布局管理器)QHBoxLayout (水平布局管理器)

QVBoxLayout 垂直布局

QVBoxLayout是垂直布局管理器,用于将窗口部件垂直排列。其按照添加顺序依次排列窗口控件,直到空间不足为止。

核心属性

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

核心方法

|---------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------|
| 方法 | 说明 |
| addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment()) | 将控件添加到布局管理器中,第一个参数是控件指针,第二个参数是拉伸系数(后续讲解) |
| addSpacerItem(QSpacerItem *spacerItem) | 在布局管理器中添加一个可调整大小的空白控件(QSpacerItem),可设置最小尺寸、最大尺寸和伸展系数。在其构造函数指定相关系数 |
| addSpacing(int size) | 添加固定大小的空白间隔,指定一个整数作为参数,表示在布局中插入的像素间隔 |
| addStretch(int stretch = 0) | 添加一个伸展因子,可以理解为一个占位符,会根据布局中其他窗口控件的大小,自动调整器大小以填充可用空间 参数表示伸展因子的大小 |
| addStruct(int size) | 添加一个固定大小的占位控件 与addSpacing 类似,但addStruct创建的不是一个真正的控件,而是一次固定大小的占位 |
| addLayout(QLayout *layout) | 布局管理器嵌套布局管理器 |
| insertWidget(int index, QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment()) | 上述方法都有insert系列,多了第一个参数index,表示插入的下标,若index = 0,则插入后的widget为第0个 |
| insert ........ | |

布局管理器只用于界面布局,所以没有提供信号


代码示例:使用垂直布局管理器规范三个按钮

编写widget.cpp,在构造函数中初始化相应控件

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QVBoxLayout *layout = new QVBoxLayout();
    QPushButton *button1 = new QPushButton("按钮1");
    QPushButton *button2 = new QPushButton("按钮2");
    QPushButton *button3 = new QPushButton("按钮3");
    //将控件添加至布局管理器中
    layout->addWidget(button1);
    layout->addWidget(button2);
    layout->addWidget(button3);
    //将布局管理器应用在界面上
    this->setLayout(layout);
}

因为整个窗口就是一个界面,将布局管理器应用在该界面,其中添加的控件就会自适应窗口的大小


Qt Designer添加布局管理器,类型有如下,通过拖拽的方式添加到窗口中

通过 Qt Designer 添加的布局管理器,其可调节管理范围,本质是在大窗口上创建了一个小窗口,然后在这个小窗口中启用布局管理器

如此布局管理器中的控件就不会随窗口大小改变而自适应,因为这些小窗口没有自适应大窗口的改变,自然其中的控件也不会变化

QHBoxLayout 水平布局

QHBoxLayoutQVBoxLayout 都继承自 QBoxLayout,属性和方法都一致,此处不过多赘述

代码示例:使用水平布局管理三个按钮

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //QVBoxLayout *layout = new QVBoxLayout();
    QHBoxLayout *layout = new QHBoxLayout();
    QPushButton *button1 = new QPushButton("按钮1");
    QPushButton *button2 = new QPushButton("按钮2");
    QPushButton *button3 = new QPushButton("按钮3");
    //将控件添加至布局管理器中
    layout->addWidget(button1);
    layout->addWidget(button2);
    layout->addWidget(button3);
    //将布局管理器应用在界面上
    this->setLayout(layout);
}

代码示例:嵌套布局管理器。实现三行按钮,前两行各有一个按钮,最后一行有两个按钮

编写 widget.cpp 的构造函数

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //垂直布局
    QVBoxLayout *main_layout = new QVBoxLayout();
    QPushButton *button1 = new QPushButton("按钮1");
    QPushButton *button2 = new QPushButton("按钮2");
    main_layout->addWidget(button1);
    main_layout->addWidget(button2);
    //水平布局
    QHBoxLayout *layout = new QHBoxLayout();
    QPushButton *button3 = new QPushButton("按钮3");
    QPushButton *button4 = new QPushButton("按钮4");
    layout->addWidget(button3);
    layout->addWidget(button4);
    //将水平布局设置进垂直布局中
    main_layout->addLayout(layout);
    //将布局设置进窗口
    this->setLayout(main_layout);
}

QGridLayout 网格布局

QGridLayout用于实现网格布局的效果,将界面分成若干行和列,可以将控件放置在网格的指定位置上,支持跨越多行和多列的布局,可以达到 M * N 的网格效果

核心属性

QGridLayout 整体属性和 QBoxLayout 相似,但是设置 spacing 的时候是按照垂直水平两个方向设置的

|---------------------------|---------------|
| 属性 | 说明 |
| layoutLeftMargin | 左侧边距 |
| layoutRightMargin | 右侧边距 |
| layoutTopMargin | 上方边距 |
| layoutBottomMargin | 下方边距 |
| layoutSpacing | 相邻元素之间的间距 |
| layoutHorizontalSpacing | 相邻元素之间水平方向的间距 |
| layoutVerticalSpacing | 相邻元素之间垂直方向的间距 |
| layoutRowStretch | 行方向的拉伸系数 |
| layoutColumnStretch | 列方向的拉伸系数 |

核心方法

QGridLayout 整体方法也与 QBoxLayout 相似,不过因为QGridLayout管理的控件为多行多列,所以再设置控件/布局管理器时,需要指明行列号

|--------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| 方法 | 说明 |
| addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = Qt::Alignment()) | 将控件添加到布局管理器中,第一个参数是控件指针,二三参数是指定的行列号 |
| addWidget(QWidget *widget, int fromRow, int formColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment()) | 将控件放置在从 (fromRow, formColumn) 开始,控件宽度为 columnSpan ,高度为 rowSpan 如果 columnSpan/rowSpan为-1,那么将填充至列/行结尾 |
| setVerticalSpacing(int spacing) | 只在垂直方向设置空白间隔 |
| setHorizontalSpacing(int spacing) | 只在水平方向设置空白间隔 |
| setSpacing(int spacing) | 在垂直和水平方向都添加空白间隔 |
| setColumnStretch(int column, int stretch) | 设置 column 列的拉伸系数 |
| setRowStretch(int row, int stretch) | 设置 row 行的拉伸系数 |
| addLayout(QLayoutItem *item, int row, int column, Qt::Alignment alignment = Qt::Alignment()) | 嵌套布局管理器,将布局管理器设置到指定行列 |
| addLayout(QLayoutItem *item, int fromRow, int formColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment()) | 和第二个addWidget类似,多了宽度和高度 |


代码示例:将按钮按两行两列排列

编写 widget.cpp的构造函数

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QGridLayout *layout = new QGridLayout();
    QPushButton *button1 = new QPushButton("按钮1");
    QPushButton *button2 = new QPushButton("按钮2");
    QPushButton *button3 = new QPushButton("按钮3");
    QPushButton *button4 = new QPushButton("按钮4");
    //将按钮添加到布局管理器中
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 0, 1);
    layout->addWidget(button3, 1, 0);
    layout->addWidget(button4, 1, 1);
    //将布局管理设置进窗口
    this->setLayout(layout);
}

调整指定的行列,观察不同效果

可以看到,并不是设置到第几行第几列就会将界面划分到几行几列,而是根据有多少行列值不同而划分

Stretch 拉伸系数

有时我们并不想布局管理器中所有的控件大小都相同,此时就可以通过 stretch 改变行列间控件的大小。

通过设置拉伸系数,会将一行/列的控件按各自的拉伸系数,等比例的划分行/列


代码示例:对两行三列的按钮,进行大小改变

编写widget.cpp的构造函数

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QGridLayout *layout = new QGridLayout();
    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");
    //将按钮添加到布局管理器中
    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);
    //设置列拉伸系数为1:2:3
    layout->setColumnStretch(0, 1);//第0列拉伸系数为1
    layout->setColumnStretch(1, 2);//第1列拉伸系数为2
    layout->setColumnStretch(2, 3);//第2列拉伸系数为3
    //将布局管理设置进窗口
    this->setLayout(layout);
}

若想设置行拉伸系数,直接设置并没有效果,因为控件大小还受 sizePolicy 影响

QSizePolicy 尺寸策略

QsizePolicy类用于描述控件的大小策略,即小控件在其父布局中如何调整自身大小以适应可用空间

核心属性

|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 说明 |
| HorizontalPolicy | 水平方向的调整方式 |
| VerticalPolicy | 垂直方向的调整方式 |
| PolicyTypes | 策略类型 * QSizePolicy::Fixed:固定大小,不会被调整 * QSizePolicy::Minimum:控件可以缩小,但不能小于最小大小 * QSizePolicy::Maximum:控件可以放大,但不能大于最大大小 * QSizePolicy::Preferred:控件会尽可能接近其建议的大小,也可以调整 * QSizePolicy::Expanding:控件会尽可能扩展以填充可用空间 * QSizePolicy::Shrinking:控件会尽可能缩小以适应空间 * QSizePolicy::MinimumExpanding:达到最小大小后仍可以扩展 * QSizePolicy::Ignored:由其他因素(如布局)决定大小 |


如果要设置行拉伸因子,还需要将控件的行尺寸策略设置为 QSizePolicy::Expanding

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //三行两列,行拉伸比例为1:0:3
    QGridLayout *layout = new QGridLayout();
    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->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);
    //设置行拉伸系数为1:0:3
    layout->setRowStretch(0, 1);
    layout->setRowStretch(1, 0);//第1列行伸系数为0,设置为0,即为固定大小,不参与拉伸
    layout->setRowStretch(2, 3);
    //将布局管理设置进窗口
    this->setLayout(layout);
}

使用 QGridLayout 可以代替很多 QHBoxLayoutQVBoxLayout 嵌套的场景

同时 QGridLayout 也可以嵌套 QHBoxLayoutQVBoxLayout ,反之如此,QHBoxLayout 也可以嵌套 QGridLayout

QFormLayout 表单布局

QFormLayout 属于 QGridLayout 的特殊情况,专门用于实现两列表单的布局,将表单字段(如标签和输入框)组织成标签和对应控件的对,通常用于配置界面或设置界面

核心方法

|-----------------------------------------------------------------------------------|------------------------------------|
| 方法 | 说明 |
| addRow(QWidget *widget) addRow(QLayout *layout) | 添加一行,只有单个控件/布局器 |
| addRow(QWidget *label, QWidget *field) addRow(QWidget *label, QLayout *field) | 添加一行,有标签和控件/布局器组成的对 |
| insert(int row, QWidget *label, QWidget *field) ....... | 插入一行表单 insert方法与add类似,就多了第一个参数 row |
| removeRow(int row) | 删除一行表单 |
| rowCount() | 获取当前行数 |

代码示例:有姓名、密码两个表单

编写widget.cpp的构造函数

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QFormLayout *layout = new QFormLayout();
    //创建标签
    QLabel *label_name = new QLabel("姓名");
    QLabel *label_password = new QLabel("密码");
    //创建输入框
    QLineEdit *edit_name = new QLineEdit();
    QLineEdit *edit_password = new QLineEdit();
    edit_password->setEchoMode(QLineEdit::Password);
    //创建提交按钮
    QPushButton *button = new QPushButton("提交");
    //添加表单
    layout->addRow(label_name, edit_name);
    layout->addRow(label_password, edit_password);
    layout->addRow(button);
    //设置布局管理器
    this->setLayout(layout);
}

QSpacerItem 空白区域

QSpacerItem 主要用于在布局中添加可调整的空白区域,使界面更加美观

核心属性

|--------|------------------------------------------------|
| 属性 | 说明 |
| width | 宽度 |
| height | 高度 |
| hData | 水平方向的 sizePolicy Expanding、Ignored、Preferred等等 |
| VDate | 垂直方向的 sizePolicy 选项同上 |

代码示例:layout 是一个水平布局管理器,有两个按钮,在中间和后面添加 QSpacerItem,观察效果

结束语

感谢你的阅读,如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要

相关推荐
Ajiang28247353041 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空1 小时前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10224 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
‘’林花谢了春红‘’6 小时前
C++ list (链表)容器
c++·链表·list
----云烟----6 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024066 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康7 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神7 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式