目录
一、简述
QLayout类是布局管理器的基类。
QLayout是由具体类 QBoxLayout、QGridLayout、QFormLayout 和 QStackedLayout继承的抽象基类。
Qlayout类是抽象类,所以不可以被实例化。
下图是类的继承关系图:

QLayoutItem类提供QLayout操作的抽象项。
Qlayout的管理又是以QLayoutItem为单位。所以,在addWidget的操作中,QLayout会创建一个QLayoutItem的子类。QWidgetItem类来对应的包装代理添加进来的子控件。QWidgetItem对象最终会将QLayout布局管理体系中的布局参数信息装换、设置到它所代理的QWidget对象上。
所有 QWidget子类都可以使用布局来管理它们的子类。QWidget::setLayout()函数可以为一个控件布局。如果QWidget上已经设置了布局管理器,QWidget将不允许您安装另一个。必须先删除现有布局管理器(由layout()返回),然后才能使用新布局调用setLayout()。
当以这种方式在widget上设置布局时,它负责以下任务:
1、布置子控件。
2、最高层窗口可感知的默认大小。
3、最高层窗口可感知的最小大小。
4、调整大小的处理。
5、当内容改变的时候自动更新:
字体大小、文本或者子控件的其它内容。
隐藏或者显示子控件。
移除一些子控件。
注意:布局销毁后,布局内的控件不会被销毁,控件不能以布局作为parent。
可以在布局中使用addLayout()来嵌套布局,内部的布局就会变成它的子布局。
二、详解
1、QBoxLayout
QBoxLayout类水平或垂直排列子部件(widget或layout)。QBoxLayout将它获得的空间分成一行小框框,每一个小框托管一个子部件。
创建QBoxLayout的最简单方法是使用它的一个子类,例如QHBoxLayout(水平布局)或QVBoxLayout(垂直布局)。也可以直接使用QBoxLayout构造函数,将其方向指定为LeftToRight、RightToLeft、TopToBottom或BottomToTop。
enum QBoxLayout::Direction
Constant | Value | Description |
QBoxLayout::LeftToRight | 0 | 水平从左到右 |
QBoxLayout::RightToLeft | 1 | 水平从右到左 |
QBoxLayout::TopToBottom | 2 | 垂直从上到下 |
QBoxLayout::BottomToTop | 3 | 垂直从下到上 |
如果QBoxLayout不是顶级布局(即它没有管理小部件的所有区域和子项),则必须将其添加到其父布局中,然后才能对其进行任何操作。添加布局的常规方法是调用parentLayout->addLayout()。
可以使用以下四个方法之一将部件加到QBoxLayout:
-
addWidget(QWidget *widget, int stretch = 0,Qt::Alignment alignment = Qt::Alignment())
将小部件添加到QBoxLayout并设置小部件的拉伸因子和对齐方式。(默认对齐方式为0,这意味着小部件将填充整个单元格。)
-
addSpacing(int size)
将大小为的不可拉伸空间(QSpacerItem)添加到此框布局的末尾。QBoxLayout提供默认边距和间距。此功能可增加额外空间。
-
addStretch(int stretch = 0)
将最小大小和拉伸系数为零的可拉伸空间(QSpacerItem)添加到此框布局的末尾。
-
addLayout(QLayout *layout, int stretch = 0)
将包含另一个QLayout的框添加到布局的末尾,并设置该布局的拉伸因子。
另外还可以使用insertWidget()、insertSpacing()、insertStretch()或insertLayout()在布局中的指定位置插入框。
QBoxLayout还包括两种边距宽度:
setContentsMargins()设置小部件每一侧的外边框宽度。这是沿QBoxLayout四边的保留空间的宽度。
setSpacing()设置相邻框之间的宽度。(您可以使用addSpacing()在特定位置获得更多空间。)
注意:边距默认值由样式提供。大多数Qt样式指定的默认边距为9(子窗口小部件)和11(窗口)。间距默认为与顶层布局的边距宽度相同,或与父布局相同。
要从布局中删除小部件,请调用removeWidget()。在小部件上调用Qwidget::hide()也会有效地从布局中移除小部件,直到调用Qwidget::show()。
实例:
QWidget *window = new QWidget;
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
layout->addWidget(button4);
layout->addWidget(button5);
window->setLayout(layout);
window->show();
首先,我们在布局中创建所需的小部件。然后,我们创建QHBoxLayout对象并将小部件添加到布局中。最后,我们调用QWidget::setLayout()将QHBoxLayout对象安装到小部件上。此时,布局中的小部件将被重新编程,以将窗口作为其父窗口。

如果我们创建QVBoxLayout对象去添加小部件,效果如下:

2、QGridLayout
QGridLayout将其获得的空间划分为行和列,并将其管理的每个小部件放入正确的单元格中。
每列都有最小宽度和拉伸系数。最小宽度是使用setColumnMinimumWidth()设置的最大宽度,也是该列中每个小部件的最小宽度。拉伸因子是使用setColumnStretch()设置的,它决定了该列将获得多少可用空间并超过其所需的最小值。
列和行的行为相同,行也有相应的函数设置最小宽度和拉伸系数。
通常,使用addWidget()或addLayout()将每个托管小部件或布局放入其自己的单元格中。
void QGridLayout::addLayout(QLayout*layout, int row, int column, Qt::Alignment alignment = Qt::Alignment())
void QGridLayout::addWidget(QWidget*widget, int row, int column, Qt::Alignment alignment = Qt::Alignment())
将给定的小部件或布局添加到单元格网格的某行、某列。默认情况下,左上角位置为(0,0)。默认对齐方式为0,这意味着小部件将填充整个单元格。
void QGridLayout::addLayout(QLayout*layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignmentalignment = Qt::Alignment())
void QGridLayout::addWidget(QWidget*widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment= Qt::Alignment())
这两个都是重载函数。将小部件或布局添加到单元格网格中,跨越多行/多列。单元格将从row、column开始,跨越rowSpan行和columnSpan列。小部件将具有给定的对齐方式。如果rowSpan和/或columnSpan为-1,则小部件或布局将分别延伸到底部和/或右边缘。
要从布局中删除小部件,请调用removeWidget()。在小部件上调用QWidget::hide()也会有效地从布局中移除小部件,直到调用QWidget::show()。
QGridLayout还包括两个页边空白宽度:ContentsMargins和spacing()。ContentsMargins是QGridLayout四条边上保留空间的宽度。spacing()是相邻框之间自动分配的间距的宽度。
函数spacing():如果垂直间距等于水平间距,则此函数返回该值;否则返回-1。
通常情况下我们使用verticalSpacing()和horizontalSpacing(),相应的也有set函数。
注意:默认内容边距值由样式提供。Qt样式指定的默认值是9(对于子窗口小部件)和11(对于窗口)。间距默认为与顶层布局的边距宽度相同,或与父布局相同。
实例:
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent)
{
if(this->centralWidget()) {
delete this->centralWidget();
}
QWidget *cWidget = new QWidget(this);
this->setCentralWidget(cWidget);
QGridLayout *glayout = new QGridLayout();
QStringList text = {"7", "8", "9","4", "5", "6", "1", "2","3","+/-","0","."};
int idx = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
idx = i * 3 + j;
QPushButton *btn = new QPushButton(text.at(idx));
glayout->addWidget(btn, i, j);
}
}
cWidget->setLayout(glayout);
}
实现了一个数字小键盘界面,效果如下:

3、QFormLayout
QFormLayout以两列形式布局其子项。左列由标签组成,右列由小部件组成。
QGridLayout也能实现两列形式的布局,但QFormLayout有它独特的优点:
-
遵循不同平台的外观和行为准则。
例如,macOS和KDE默认标签应该右对齐,而Windows和GNOME应用程序通常使用左对齐。
-
支持包裹长行。
对于具有小型显示器的设备,QFormLayout可以设置为换行长行,甚至换行所有行。
-
用于创建“标签-字段”的API。
addRow()重载使用QString和QWidget*在后台创建一个QLabel,并自动设置其好友。
例如:
QFormLayout*formLayout = new QFormLayout;
formLayout->addRow(tr("&Name:"),nameLineEdit);
formLayout->addRow(tr("&Email:"),emailLineEdit);
formLayout->addRow(tr("&Age:"),ageSpinBox);
setLayout(formLayout);
4、QStackedLayout
QStackedLayout类提供了一组小部件,一次只能看到一个小部件。
QStackedLayout可用于创建与QTabWidget提供的用户界面类似的用户界面。在QStackedLayout之上还构建了一个方便的QStackeedWidget类。
基于以上原因,QStackedLayout在一般项目中很少使用。
代码实例:
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent)
{
if(this->centralWidget()) {
delete this->centralWidget();
}
QWidget *cWidget = new QWidget(this);
this->setCentralWidget(cWidget);
QWidget *firstPageWidget = new QWidget;
firstPageWidget->setStyleSheet("background:rgb(0,255,0);");
QWidget *secondPageWidget = new QWidget;
secondPageWidget->setStyleSheet("background:rgb(255,255,0);");
QWidget *thirdPageWidget = new QWidget;
thirdPageWidget->setStyleSheet("background:rgb(0,255,255);");
QStackedLayout *stackedLayout = new QStackedLayout;
stackedLayout->addWidget(firstPageWidget);
stackedLayout->addWidget(secondPageWidget);
stackedLayout->addWidget(thirdPageWidget);
QComboBox *pageComboBox = new QComboBox;
pageComboBox->addItem(tr("Page 1"));
pageComboBox->addItem(tr("Page 2"));
pageComboBox->addItem(tr("Page 3"));
connect(pageComboBox,QOverload<int>::of(&QComboBox::activated),
stackedLayout, &QStackedLayout::setCurrentIndex);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(pageComboBox);
mainLayout->addLayout(stackedLayout);
cWidget->setLayout(mainLayout);
}
每个widget设置了不同的背景色,通过选择不同项,显示不同widget,效果如下:



在Qt中,layoutSizeConstraint是用于控制布局的大小约束的属性。它可以设置在布局中的小部件大小发生变化时,布局的行为。
layoutSizeConstraint是一个枚举类型,它有以下几个选项:
-
QLayout::SetDefaultConstraint:默认约束。布局将按照其内容和部件的最小尺寸进行调整。
-
QLayout::SetFixedSize:固定大小约束。布局的大小将被固定,不会根据内容和部件的大小进行调整。
-
QLayout::SetMinimumSize:最小尺寸约束。布局的大小将根据内容和部件的最小尺寸进行调整,但不会超过布局的最小尺寸。
-
QLayout::SetMaximumSize:最大尺寸约束。布局的大小将根据内容和部件的大小进行调整,但不会超过布局的最大尺寸。
-
QLayout::SetMinAndMaxSize:最小和最大尺寸约束。布局的大小将根据内容和部件的大小进行调整,但会受到布局的最小和最大尺寸的限制。
可以使用以下方法来设置布局的大小约束:
QLayout *layout = new QHBoxLayout;
layout->setSizeConstraint(QLayout::SetFixedSize);
上述示例将布局的大小约束设置为固定大小,这意味着布局的大小将保持不变,不会根据内容和部件的大小进行调整。
在实际使用中,根据布局的需求和应用场景选择合适的大小约束,以便获得所期望的布局行为