7.布局管理器
之前使用Qt在界面上创建的控件,都是通过"绝对定位"的方式来设定的
也就是每个控件所在的位置,都需要计算坐标,最终通过setGeometry
或者
move
方式摆放过去,
这种设定方式其实并不方便,尤其是界面如果内容比较多,不好计算,而且一个窗口大小往往是可以调整的,按照绝对定位的方式,也无法自适应窗口大小
因此Qt引入"布局管理器"(Layout)机制,来解决上述问题.
布局管理器并非Qt独有.其他的GUI开发框架,像Android,前端等也有类似的机制
①垂直布局
使用QVBoxLayout
表示垂直的布局管理器,V是vertical
的缩写
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
Layout只是用于界面布局,并没有提供信号,
①使用QVBoxLayout
管理多个控件
#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* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
//创建布局管理器,并把按钮添加进去
//如果创建的时候指定父元素为this,则后面不需要setLayout方法了
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(btn1);
layout->addWidget(btn2);
layout->addWidget(btn3);
//把布局管理器设置到Widget中
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
②创建两个QVBoxLayout
按钮已经自动排列好,只不过当前这些按钮的位置不能随着窗口大小自动变化
通过Qt Designer创建的布局管理器,其实是先创建了一个widget,.设置过geometry
属性的,再把这个layout
设置到这个widget
中
实际上,一个widget
只能包含一个layout
打开ui文件的原始ml,可以看到其中的端倪
这种情况下layout并非是窗口widget的布局管理器,因此不会随着窗口大小改变
②水平布局
使用QHBox Layout
,表示垂直的布局管理器.H是horizontal
的缩写
核心属性(和QVBoxLayout
属性是一致的)
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
①使用QHBoxLayout
管理控件
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QHBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建三个按钮,并且把按钮添加到布局控制器中
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
//创建布局管理器
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(btn1);
layout->addWidget(btn2);
layout->addWidget(btn3);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
②嵌套下的layout
Layout里面可以再嵌套上其他的layout,从而达到更复杂的布局效果
#include "widget.h"
#include "ui_widget.h"
#include<QVBoxLayout>
#include<QHBoxLayout>
#include<QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建顶层layout
QVBoxLayout* layoutParent = new QVBoxLayout();
this->setLayout(layoutParent);
//添加两个按钮进去
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
layoutParent->addWidget(btn1);
layoutParent->addWidget(btn2);
//创建子layout
QHBoxLayout* layoutChild = new QHBoxLayout();
//添加两个按钮进去
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
layoutChild->addWidget(btn3);
layoutChild->addWidget(btn4);
//把子layout添加到父layout中
layoutParent->addLayout(layoutChild);
}
Widget::~Widget()
{
delete ui;
}
③网格布局
Qt中还提供了QGridLayout
用来实现网格布局的效果.可以达到M*N的这种网格的效果
核心属性
整体和QVBoxLayout
以及QHBoxLayout
相似,但是设置spacing
的时候是按照垂直水平两个方向来设置的
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutHorizontalSpacing | 相邻元素之间水平方向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直方向的间距 |
layoutRowStretch | 行方向的拉伸系数 |
layoutColumnStretch | 列方向的拉伸系数 |
①使用QGridLayout
管理元素
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QGridLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建四个按钮
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
//创建网格布局管理器,并添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1,0,0);
layout->addWidget(btn2,0,1);
layout->addWidget(btn3,1,0);
layout->addWidget(btn4,1,1);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
//假如是这种布局
//相当于QHBoxLayout
layout->addWidget(btn1,0,1);
layout->addWidget(btn2,0,2);
layout->addWidget(btn3,0,3);
layout->addWidget(btn4,0,4);
//假如是这种布局
//相当于QVBoxLayout
layout->addWidget(btn1, 1, 0);
layout->addWidget(btn2, 2, 0);
layout->addWidget(btn3, 3, 0);
layout->addWidget(btn4, 4, 0);
此处也要注意,设置行和列的时候,如果设置的是一个很大的值,但是这个值和上一个值之间并没有其他的元素,那么并不会在中间腾出额外的空间
假如把btn4设置在第10行,但是由于3-9行没有元素.因此btn4仍然会紧挨在btn3下方,看起来和上面的0 1 2 3
的情况是相同的
②设置QGridLayout
中元素的大小比例
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QGridLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
QPushButton* btn5 = new QPushButton("按钮5");
QPushButton* btn6 = new QPushButton("按钮6");
//创建网络布局管理器,添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1,0,0);
layout->addWidget(btn2,0,1);
layout->addWidget(btn3,0,2);
layout->addWidget(btn4,1,0);
layout->addWidget(btn5,1,1);
layout->addWidget(btn6,1,2);
//设置拉伸比例
//第0列拉伸比例为1
layout->setColumnStretch(0,1);
//第1列拉伸比例为0,即为固定大小,不参与拉伸
layout->setColumnStretch(1,0);
//第2列拉伸比例为3,即为第2列的宽度是第0列的3倍
layout->setColumnStretch(2,3);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
另外,QGridLayout也提供了setRowStretch设置行之间的拉伸系数
上述案例中,直接设置setRowStretch效果不明显,因为每个按钮的高度是固定的.需要把按钮的垂直方向的sizePolicy属性设置为QSizePolicy::Expanding
尽可能填充满布局管理器,才能看到效果
③设置垂直方向的拉伸系数
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>
#include<QGridLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn1 = new QPushButton("按钮1");
QPushButton* btn2 = new QPushButton("按钮2");
QPushButton* btn3 = new QPushButton("按钮3");
QPushButton* btn4 = new QPushButton("按钮4");
QPushButton* btn5 = new QPushButton("按钮5");
QPushButton* btn6 = new QPushButton("按钮6");
//设置按钮的sizePolice,此时按钮的水平和垂直方向都会尽量舒展开
btn1->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn2->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn3->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn4->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn5->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn6->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
//创建网络布局管理器,并添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1,0,0);
layout->addWidget(btn2,0,1);
layout->addWidget(btn3,1,0);
layout->addWidget(btn4,1,1);
layout->addWidget(btn5,2,0);
layout->addWidget(btn6,2,1);
//设置拉伸比例
//第0行拉伸比例为1
layout->setRowStretch(0,1);
//第1行拉伸比例为0,即为固定大小,不参与拉伸
layout->setRowStretch(1,0);
//第2行拉伸比例为3,即为第2列的宽度是第0列的3倍
layout->setRowStretch(2,3);
this->setLayout(layout);
}
Widget::~Widget()
{
delete ui;
}
④表单布局
除了上述的布局管理器之外,Qt还提供了QFormLayout
,属于是QGridLayout
的特殊情况,专门用于实现两列表单的布局
这种表单布局多用于让用户填写信息的场景.左侧列为提示,右侧列为输入框
#include "widget.h"
#include "ui_widget.h"
#include<QFormLayout>
#include<QLabel>
#include<QLineEdit>
#include<QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
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 在控件之间添加一段空白
属性 | 说明 |
width | 宽度 |
height | 高度 |
hData | 水平方向的sizePolicy
|
vData | 垂直方向的 选项同上 |
①创建一组左右排列的按钮
#include "widget.h"
#include "ui_widget.h"
#include<QVBoxLayout>
#include<QPushButton>
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);
//在两个Widget中间件加上空白
layout->addSpacerItem(spacer);
layout->addWidget(btn2);
}
Widget::~Widget()
{
delete ui;
}
调整QSpacerltem
不同的尺寸,即可看到不同的间距
在Qt Designer
中,也可以直接给界面上添加spacer