『QT』布局管理器

1 前言
在以往的文章中, 所有的布局都通过手动或者是跟踪控件的Geometry进行调整(大部分采用手动控制);
实际上, 在Qt中引入了一种称为布局管理器的类;
其类似是一种控件, 但实际上是一个不可见的, 但可以对控件进行布局规则约束的类;
2 垂直布局
在Qt中, 存在一种垂直布局的QVBoxLayout布局方式;
其可以将垂直布局中的控件以垂直拉伸的方式进行布局, 从而能够更加轻便的对控件进行调整;
-
核心属性
属性 说明 layoutLeftMargin左侧边距 layoutRightMargin右侧边距 layoutTopMargin上方边距 layoutBottomMargin下方边距 layoutSpacing相邻元素之间的间距
由于只是作页面布局, 并未提供信号;
2.1 QVBoxLayout 的使用
-
使用代码进行布局
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); QVBoxLayout *vLayout = new QVBoxLayout(this); QPushButton* button_1 = new QPushButton("button_1"); QPushButton* button_2 = new QPushButton("button_2"); QPushButton* button_3 = new QPushButton("button_3"); vLayout->addWidget(button_1); vLayout->addWidget(button_2); vLayout->addWidget(button_3); }创建了一个
QVBoxLayout垂直布局管理器, 并创建了三个按钮控件, 在创建按钮控件时并没有指名父对象, 实际上是因为其需要交由布局管理器进行管理, 即将内存管理挂在垂直布局管理器的对象树上;运行结果为:

可以看到, 在布局管理器中, 三个按钮控件为垂直排列, 且大小会根据外部的
Widget自行变化, 这本质上是布局管理器的功劳;
3 一个 Widget 中无法存在多个布局管理器
如题, 一个Widget中无法存在多个布局管理器;
通常情况下, 我们可以使用QtDesigner手动进行添加布局管理器, 因此可以拖动多个布局管理器进一个Widget中;

运行结果为:

可以看到, 实际上布局管理器的动态调整窗口效果并未显现;
本质是因为, 当一个Widget中同时出现多个布局管理器时, 将会为该布局管理器前先隐式创建对应的Widget;
/* ui_widget.h */
void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName("Widget");
Widget->resize(527, 395);
verticalLayoutWidget = new QWidget(Widget);
verticalLayoutWidget->setObjectName("verticalLayoutWidget");
verticalLayoutWidget->setGeometry(QRect(60, 109, 160, 181));
verticalLayout = new QVBoxLayout(verticalLayoutWidget);
verticalLayout->setObjectName("verticalLayout");
verticalLayout->setContentsMargins(0, 0, 0, 0);
pushButton = new QPushButton(verticalLayoutWidget);
pushButton->setObjectName("pushButton");
verticalLayout->addWidget(pushButton);
...
...
...
}
4 水平布局管理器
水平布局管理器为QHBoxLayout;
-
核心属性
属性 说明 layoutLeftMargin左侧边距 layoutRightMargin右侧边距 layoutTopMargin上方边距 layoutBottomMargin下方边距 layoutSpacing相邻元素之间的间距
由于只是作页面布局, 并未提供信号;
其使用与垂直布局管理器相同, 不作赘述;
5 网格布局管理器
除了垂直于水平两种布局管理器以外, Qt还提供了一种网格布局管理器QGridLayout;
其布局方式类似于表格的方式, 可以达到M*N的模式进行布局;
整体与QVBoxLayout, QHBoxLayout类似, 但是设置SPacing时按照垂直和水平两个方向进行设置;
-
核心属性
属性 说明 layoutLeftMargin左侧边距 layoutRightMargin右侧边距 layoutTopMargin上⽅边距 layoutBottomMargin下⽅边距 layoutHorizontalSpacing相邻元素之间⽔平⽅向的间距 layoutVerticalSpacing相邻元素之间垂直⽅向的间距 layoutRowStretch⾏⽅向的拉伸系数 layoutColumnStretch列⽅向的拉伸系数
5.1 QGridLayout 的使用
通常在网格布局管理器中添加控件的参数要比垂直布局/水平布局要多两个参数, 分别为该控件所需的第几行, 第几列的位置;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGridLayout *gridLayout = new QGridLayout(this);
QPushButton *button_00 = new QPushButton("button_00");
QPushButton *button_01 = new QPushButton("button_01");
QPushButton *button_10 = new QPushButton("button_10");
QPushButton *button_11 = new QPushButton("button_11");
gridLayout->addWidget(button_00, 0, 0);
gridLayout->addWidget(button_01, 0, 1);
gridLayout->addWidget(button_10, 1, 0);
gridLayout->addWidget(button_11, 1, 1);
}
运行结果为:

除此之外, 其还可以使用类似垂直布局或是水平布局的方式, 即把对应的行改为同一行, 或是列改为同一列即可;
除此之外, 这里的位置并不是绝对位置, 而是相对进行比较大小的位置;
假设现在对代码中在QGridLayout中添加控件的代码进行调整;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGridLayout *gridLayout = new QGridLayout(this);
QPushButton *button_00 = new QPushButton("button_00");
QPushButton *button_01 = new QPushButton("button_01");
QPushButton *button_10 = new QPushButton("button_10");
QPushButton *button_11 = new QPushButton("button_11");
gridLayout->addWidget(button_00, 0, 0);
gridLayout->addWidget(button_01, 0, 100);
gridLayout->addWidget(button_10, 200, 0);
gridLayout->addWidget(button_11, 200, 100);
}
对应的运行结果为:

可以观察到, 实际的数据只是为了进行比较先后, 并不是绝对的行列位置;
5.2 拉伸系数
对 QGridLayout 而言存在一个拉伸系数的概念, 本质上这个拉伸系数的概念就是按照多少的比例来显示控件;
通常使用setColumnStretch()来设置列的拉伸系数;
假设存在一个程序中的QGridLayout中有六个按钮, 组成两行三列, 这三列的宽度比例设置为1:1:2, 并且当Widget发生变化时, QGridLayout中的控件将会按照对应的比例进行缩放;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGridLayout *gridLayout = new QGridLayout(this);
QPushButton *button_1 = new QPushButton("button_1");
QPushButton *button_2 = new QPushButton("button_2");
QPushButton *button_3 = new QPushButton("button_3");
QPushButton *button_4 = new QPushButton("button_4");
QPushButton *button_5 = new QPushButton("button_5");
QPushButton *button_6 = new QPushButton("button_6");
gridLayout->addWidget(button_1,0,0);
gridLayout->addWidget(button_2,0,1);
gridLayout->addWidget(button_3,0,2);
gridLayout->addWidget(button_4,1,0);
gridLayout->addWidget(button_5,1,1);
gridLayout->addWidget(button_6,1,2);
gridLayout->setColumnStretch(0, 1);
gridLayout->setColumnStretch(1, 1);
gridLayout->setColumnStretch(2, 2);
}
运行结果为:

除此之外, 也可以对行进行拉伸系数的设置;
但通常情况下, 直接对行进行拉伸系数的设置是无效的;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGridLayout *gridLayout = new QGridLayout(this);
QPushButton *button_1 = new QPushButton("button_1");
QPushButton *button_2 = new QPushButton("button_2");
QPushButton *button_3 = new QPushButton("button_3");
QPushButton *button_4 = new QPushButton("button_4");
QPushButton *button_5 = new QPushButton("button_5");
QPushButton *button_6 = new QPushButton("button_6");
gridLayout->addWidget(button_1,0,0);
gridLayout->addWidget(button_2,0,1);
gridLayout->addWidget(button_3,1,0);
gridLayout->addWidget(button_4,1,1);
gridLayout->addWidget(button_5,2,0);
gridLayout->addWidget(button_6,2,1);
gridLayout->setRowStretch(0, 1);
gridLayout->setRowStretch(1, 1);
gridLayout->setRowStretch(2, 2);
}
但其运行结果为:

明显拉伸系数并未起到作用;
通常情况下, 这是因为Widget的属性, SizePolicy的影响;
该属性的一些值为如下:
-
QSizePolicy::Ignored忽略控件的尺⼨, 不对布局产⽣影响;
-
QSizePolicy::Minimum控件的最⼩尺⼨为固定值, 布局时不会超过该值;
-
QSizePolicy::Maximum控件的最⼤尺⼨为固定值, 布局时不会⼩于该值;
-
QSizePolicy::Preferred控件的理想尺⼨为固定值, 布局时会尽量接近该值;
-
QSizePolicy::Expanding控件的尺⼨可以根据空间调整, 尽可能占据更多空间;
-
QSizePolicy::Shrinking控件的尺⼨可以根据空间调整, 尽可能缩⼩以适应空间;
通常可以对QWidget或者其子类控件通过setRowStretch(QSizePolicyForRow, QSizePolicyForColumn)来设置对应的QSizePolicy属性;
我们可以将对应按钮的QSizePolicy属性长宽都设置为Expanding, 以更好适应空间变化;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGridLayout *gridLayout = new QGridLayout(this);
QPushButton *button_1 = new QPushButton("button_1");
QPushButton *button_2 = new QPushButton("button_2");
QPushButton *button_3 = new QPushButton("button_3");
QPushButton *button_4 = new QPushButton("button_4");
QPushButton *button_5 = new QPushButton("button_5");
QPushButton *button_6 = new QPushButton("button_6");
gridLayout->addWidget(button_1,0,0);
gridLayout->addWidget(button_2,0,1);
gridLayout->addWidget(button_3,1,0);
gridLayout->addWidget(button_4,1,1);
gridLayout->addWidget(button_5,2,0);
gridLayout->addWidget(button_6,2,1);
// 设置SizePolicy属性(长宽都设置为Expanding)
button_1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button_2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button_3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button_4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button_5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button_6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// 设置拉伸系数
gridLayout->setRowStretch(0, 1);
gridLayout->setRowStretch(1, 1);
gridLayout->setRowStretch(2, 2);
}
-
运行结果为
