【Qt】布局管理器

发布于:2024-08-14 ⋅ 阅读:(43) ⋅ 点赞:(0)

界面中各元素排列有序往往会更加的美观,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,在构造函数中初始化相应控件

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 水平布局

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

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

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 的构造函数

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的构造函数

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的构造函数

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

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的构造函数

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,观察效果

结束语

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