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