文章目录
- [1 :peach:写在前面:peach:](#1 :peach:写在前面:peach:)
- [2 :peach:垂直布局:peach:](#2 :peach:垂直布局:peach:)
- [3 :peach:水平布局:peach:](#3 :peach:水平布局:peach:)
- [4 :peach:网格布局:peach:](#4 :peach:网格布局:peach:)
- [5 :peach:表单布局:peach:](#5 :peach:表单布局:peach:)
1 🍑写在前面🍑
之前使⽤ Qt 在界⾯上创建的控件, 都是通过 "绝对定位" 的⽅式来设定的。也就是每个控件所在的位置, 都需要计算坐标, 最终通过 setGeometry
或者 move ⽅式摆放过去。
这种设定⽅式其实并不⽅便,尤其是界⾯如果内容⽐较多, 不好计算。⽽且⼀个窗⼝⼤⼩往往是可以调整的, 按照绝对定位的⽅式, 也⽆法⾃适应窗⼝⼤⼩。因此 Qt 引⼊ 布局管理器 (Layout) 机制, 来解决上述问题。
2 🍑垂直布局🍑
使⽤ QVBoxLayout
表⽰垂直的布局管理器,V 是 vertical 的缩写。
核⼼属性:
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutSpacing | 相邻元素之间的间距 |
Layout 只是⽤于界⾯布局, 并没有提供信号。
代码示例:
cpp
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);
}
验证结果:
使用代码的方式时我们拖拽窗口时,按钮的位置也会随着窗口的调整而改变。
我们还可以使用图形化界面的方式来进行垂直布局:
但是注意使用图形化界面的方式时我们拖拽窗口,按钮的位置不会随着窗口的调整而改变。
3 🍑水平布局🍑
使⽤ QHBoxLayout
表⽰垂直的布局管理器,H 是 horizontal 的缩写。
核⼼属性 (和 QVBoxLayout 属性是⼀致的)
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutSpacing | 相邻元素之间的间距 |
代码⽰例:
cpp
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);
// 设置 layout 到 widget 上
this->setLayout(layout);
}
结果验证:
同理我们也可以使用图形化界面的方式来创建水平布局。这里就不再演示了。
4 🍑网格布局🍑
Qt 中还提供了 QGridLayout
⽤来实现⽹格布局的效果,可以达到 M * N 的这种⽹格的效果。
核⼼属性:整体和 QVBoxLayout
以及 QHBoxLayout
相似,但是设置 spacing
的时候是按照垂直⽔平两个⽅向来设置的。
属性 | 说明 |
---|---|
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutHorizontalSpacing | 相邻元素之间⽔平⽅向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直⽅向的间距 |
layoutRowStretch | ⾏⽅向的拉伸系数 |
layoutColumnStretch | 列⽅向的拉伸系数 |
代码⽰例:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 4 个按钮
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, 2);
layout->addWidget(btn3, 1, 1);
layout->addWidget(btn4, 1, 3);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
结果验证:
我们再来看看使用下面的代码会出现什么情况:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 4 个按钮
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, 1, 0);
layout->addWidget(btn3, 2, 0);
layout->addWidget(btn4, 5, 0);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
结果验证:
此处也要注意, 设置⾏和列的时候, 如果设置的是⼀个很⼤的值, 但是这个值和上⼀个值之间并没有其他的元素, 那么并不会在中间腾出额外的空间。
代码⽰例: 设置 QGridLayout 中元素的⼤⼩⽐例
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 6 个按钮
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的话为默认大小
// 第 0 列拉伸⽐例设为 3;
layout->setColumnStretch(0, 3);
// 第 1 列拉伸⽐例设为 2,
layout->setColumnStretch(1, 2);
// 第 2 列拉伸⽐例设为 1
layout->setColumnStretch(2, 1);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
结果验证:
另外, QGridLayout
也提供了 setRowStretch
设置⾏之间的拉伸系数。上述案例中, 直接设置 setRowStretch
效果不明显, 因为每个按钮的⾼度是固定的,需要把按钮的垂直⽅向的 sizePolicy
属性设置为 QSizePolicy::Expanding
尽可能填充满布局管理器, 才能看到效果。
代码⽰例: 设置垂直⽅向的拉伸系数。
使⽤ setSizePolicy
设置按钮的尺⼨策略,可选的值如下:
- QSizePolicy::Ignored : 忽略控件的尺⼨,不对布局产⽣影响。
- QSizePolicy::Minimum : 控件的最⼩尺⼨为固定值,布局时不会超过该值。
- QSizePolicy::Maximum : 控件的最⼤尺⼨为固定值,布局时不会⼩于该值。
- QSizePolicy::Preferred : 控件的理想尺⼨为固定值,布局时会尽量接近该值。
- QSizePolicy::Expanding : 控件的尺⼨可以根据空间调整,尽可能占据更多空间。
- QSizePolicy::Shrinking : 控件的尺⼨可以根据空间调整,尽可能缩⼩以适应空间。
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建 6 个按钮
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");
// 设置按钮的 sizePolicy, 此时按钮的⽔平⽅向和垂直⽅向都会尽量舒展开
btn1->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btn2->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btn3->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btn4->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btn5->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
btn6->setSizePolicy(QSizePolicy::Preferred, 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 ⾏拉伸⽐例设为 2, 即为第 2 ⾏的宽度是第 0 ⾏的 2 倍
layout->setRowStretch(2, 2);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
结果验证:
5 🍑表单布局🍑
除了上述的布局管理器之外, Qt 还提供了 QFormLayout
, 属于是 QGridLayout
的特殊情况, 专⻔⽤于实现两列表单的布局。这种表单布局多⽤于让⽤⼾填写信息的场景,左侧列为提⽰, 右侧列为输⼊框。
代码示例:
cpp
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);
}
结果验证: