目录
前言
(一)垂直布局
(二)水平布局
(三)网格布局
(四)表单布局
(五)分组布局
(六)Spacer
总结
前言
之前使⽤Qt在界⾯上创建的控件,都是通过"绝对定位"的⽅式来设定的.
- 也就是每个控件所在的位置,都需要计算坐标,最终通过 setGeometry 或者 move ⽅式摆放过去.这种设定⽅式其实并不方便.尤其是界⾯如果内容⽐较多,不好计算.而且⼀个窗口大小往往是可以调整的,按照绝对定位的⽅式,也⽆法⾃适应窗口⼤⼩.
因此Qt引⼊"布局管理器"(Layout)机制,来解决上述问题.
Qt的布局管理器(Layout Manager)是一种用于自动排列和调整窗口或容器中的控件的工具。它们可以完成以下两件事:
- 自动调整控件的位置,包括控件之间的间距、对齐等。
- 当用户调整窗口大小时,位于布局管理器内的控件也会随之调整大小,从而保持整个界面的美观。
Qt共提供了5种布局管理器,每种布局管理器对应一个类,分别是:
- QVBoxLayout(垂直布局):将所有控件从上到下(或者从下到上)依次摆放。
- QHBoxLayout(水平布局):包含的对象都横向排列开。
- QGridLayout(网格布局):将控件放置到网格中布局,它本身会从父窗口或父布局中占据尽可能多的界面空间,然后把自己的空间划分为行和列,再把每个控件塞到设置好的一个或多个单元格中。
- QFormLayout(表单布局):通常用于创建表单界面,其中控件成对出现,例如标签和输入框。
- QStackedLayout(分组布局):可以将多个控件堆叠在一起,但一次只能显示一个控件。这通常用于实现多页面的用户界面。
这些布局管理器都继承自QLayout类,这是Qt布局管理器的抽象基类。通过继承QLayout,Qt实现了功能各异且互补的布局管理器。
与绝对位置定位相比,布局管理器具有更高的灵活性和适应性。它们可以根据窗口的大小自动调整控件的大小和位置,而无需手动调整每个控件的位置和大小。这使得在开发用户界面时更加高效和方便。
🔥 当然,布局管理器并⾮Qt独有.其他的GUI开发框架,像Android,前端等也有类似的机制.
(一)垂直布局
使用 VBoxLayout 表示垂直的布局管理器.V是 vertical 的缩写.
在Qt中,垂直布局(QVBoxLayout)是一种常用的布局管理器,它可以将控件按照垂直方向进行排列。这种布局方式非常适用于需要从上到下依次排列控件的界面设计。
核心属性:
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
🔥 注意:Layout只是⽤于界⾯布局,并没有提供信号.
QVBoxLayout是一种布局管理器,具有以下特点:
-
垂直排列:控件会按照从上到下的顺序进行排列。
-
自动调整:当父窗口或容器的大小发生变化时,QVBoxLayout会自动调整其内部控件的大小和位置,以保持布局的整齐和美观。
-
可嵌套:QVBoxLayout可以嵌套在其他布局管理器中,如QHBoxLayout或QGridLayout,以实现更复杂的界面布局。
使用方法如下:
-
创建QVBoxLayout对象:首先,需要创建一个QVBoxLayout对象。这可以通过在代码中直接创建或使用Qt Designer进行设计后生成。
-
添加控件:然后,将需要排列的控件添加到QVBoxLayout中。这可以通过调用QVBoxLayout的addWidget()方法来实现。
-
设置布局:最后,将QVBoxLayout设置为某个窗口或容器的布局。这可以通过调用窗口或容器的setLayout()方法来实现。
代码示例:使用 QVBoxLayout 管理多个控件.
1)编写代码,创建布局管理器和三个按钮.并且把按钮添加到布局管理器中.
- 使⽤ addWidget 把控件添加到布局管理器中.
- 使⽤ setLayout 设置该布局管理器到widget中.
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);
}
2)运⾏程序,可以看到此时界⾯上的按钮就存在于布局管理器中.随着窗口尺寸变化而发⽣改变.
- 此时三个按钮的尺⼨和位置,都是⾃动计算出来的.
- 通过上述代码的方式,只能给这个widget设定⼀个布局管理器.实际上也可以过Qt Design在⼀个窗⼝中创建多个布局管理器.
代码示例:创建两个 QVBoxLayout
1)在界⾯上创建两个 QVBoxLayout ,每个 QVBoxLayout 各放三个按钮.
2)运行程序,可以看到这些按钮已经⾃动排列好.只不过当前这些按钮的位置不能随着窗⼝⼤⼩⾃动变化.
(二)水平布局
使⽤ QHBoxLayout 表⽰垂直的布局管理器.H是 horizontal 的缩写.
在Qt中,水平布局(Horizontal Layout)是一种常用的布局管理方式,它允许你将多个控件(如按钮、文本框等)水平地排列在一起。
核心属性(和QVBoxLayout 属性是⼀致的)
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
代码示例:使用 QHBoxLayout 管理控件
1)编写代码,创建布局管理器和三个按钮.并且把按钮添加到布局管理器中.
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);
}
2)运⾏程序,可以看到此时界⾯上的按钮就存在于布局管理器中.随着窗⼝尺⼨变化⽽发⽣改变.
- 此时三个按钮的尺⼨和位置,都是⾃动计算出来的.
- 注意:Layout⾥⾯可以再嵌套上其他的layout,从而达到更复杂的布局效果.
代码示例: 嵌套的layout
1)在代码中创建以下内容
- 使⽤addLayout 给layout中添加⼦layout.
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);
}
2)执行程序,观察结果
- 结合 QHBoxLayout 和 QVBoxLayout ,就可以做出各种复杂的界⾯了。
(三)网格布局
Qt中还提供了QGridLayout ⽤来实现⽹格布局的效果.可以达到M*N的这种⽹格的效果
核心属性
- 整体和 QVBoxLayout 以及 QHBoxLayout 相似.但是设置spacing的时候是按照垂直⽔平两个⽅向来设置的
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上⽅边距 |
layoutBottomMargin | 下⽅边距 |
layoutHorizontalSpacing | 相邻元素之间⽔平⽅向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直⽅向的间距 |
layoutRowStretch | ⾏⽅向的拉伸系数 |
layoutColumnStretch | 列⽅向的拉伸系数 |
代码示例:使用 QGridLayout 管理元素
1)代码中创建 QGridLayout 和4个按钮.
- 使⽤ addWidget 添加控件到布局管理器中.但是添加的同时会指定两个坐标.表⽰放在第⼏⾏,第⼏列.
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, 1);
layout->addWidget(btn3, 1, 0);
layout->addWidget(btn4, 1, 1);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
2)执⾏代码,观察效果.可以看到当前的这⼏个按钮是按照2⾏2列的⽅式排列的.
3)如果调整⾏列坐标为下列代码
// 创建⽹格布局管理器, 并且添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 0, 1);
layout->addWidget(btn3, 0, 2);
layout->addWidget(btn4, 0, 3);
执行代码,可以看到这⼏个按钮都在同⼀⾏了.相当于 QHBoxLayout
4)如果调整⾏列坐标为下列代码
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 1, 0);
layout->addWidget(btn2, 2, 0);
layout->addWidget(btn3, 3, 0);
layout->addWidget(btn4, 4, 0);
执行代码,可以看到这⼏个按钮都在同⼀列了.相当于 QVBoxLayout
5)任意调整⾏列,即可看到不同的效果.
// 创建⽹格布局管理器, 并且添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 1, 1);
layout->addWidget(btn3, 2, 2);
layout->addWidget(btn4, 3, 3);
代码示例:设置 QGridLayout 中元素的大小⽐例
1)创建6个按钮,按照2⾏3列的⽅式排列
- 使用 setColumnStretch 设置每⼀列的拉伸系数.
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 列拉伸⽐例设为 1;
layout->setColumnStretch(0, 1);
// 第 1 列拉伸⽐例设为 0, 即为固定⼤⼩, 不参与拉伸
layout->setColumnStretch(1, 0);
// 第 2 列拉伸⽐例设为 3, 即为第 2 列的宽度是第 0 列的 3 倍
layout->setColumnStretch(2, 3);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
2)执行程序,可以看到每⼀列的宽度是不同的.并且随着窗⼝调整动态变化
- 另外, QGridLayout 也提供了 setRowStretch 设置⾏之间的拉伸系数.
- 上述案例中,直接设置 setRowStretch 效果不明显,因为每个按钮的⾼度是固定的.需要把按钮的垂直⽅向的 sizePolicy 属性设置为 QSizePolicy::Expanding 尽可能填充满布局管理器,才能看到效果.
使⽤ setSizePolicy 设置按钮的尺⼨策略.可选的值如下:
- QSizePolicy::Ignored :忽略控件的尺⼨,不对布局产⽣影响。
- QSizePolicy::Minimum :控件的最⼩尺⼨为固定值,布局时不会超过该值。
- QSizePolicy::Maximum :控件的最⼤尺⼨为固定值,布局时不会⼩于该值。
- QSizePolicy::Preferred :控件的理想尺⼨为固定值,布局时会尽量接近该值。
- QSizePolicy::Expanding :控件的尺⼨可以根据空间调整,尽可能占据更多空间。
- QSizePolicy::Shrinking :控件的尺⼨可以根据空间调整,尽可能缩⼩以适应空间。
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::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);
// 设置 layout 到窗⼝中.
this->setLayout(layout);
}
此时的按钮垂直⽅向都舒展开了.并且调整窗⼝尺⼨,也会按照设定的⽐例同步变化
- 总的来说,使⽤ QGridLayout 能够代替很多 QHBoxLayout 和 QVBoxLayout 嵌套的场景.毕竟嵌套的代码写起来是⽐较⿇烦的.
- 另外不要忘了, QGridLayout ⾥⾯也能嵌套 QHBoxLayout 和 QVBoxLayout ,QHBoxLayout和QVBoxLayout ⾥⾯也能嵌套 QGridLayout
(四)表单布局
除了上述的布局管理器之外,Qt还提供了 QFormLayout ,属于是 QGridLayout 的特殊情况,专门用于实现两列表单的布局.
- 这种表单布局多⽤于让⽤⼾填写信息的场景.左侧列为提⽰,右侧列为输⼊框.
代码示例:使⽤ QFormLayout 创建表单.
1)编写代码,创建 QFormLayout ,以及三个label和三个lineEdit
- 使⽤ addRow ⽅法来添加⼀⾏.每⾏包含两个控件.第⼀个控件固定是QLabel/⽂本,第⼆个控件则可以是任意控件.
- 如果把第⼀个参数填写为NULL,则什么都不显示.
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);
}
2)执行程序,可以看到以下结果.
(五)分组布局
在Qt中,分组布局(Stacked Layout)通常通过
QStackedLayout
或QStackedWidget
来实现。这种布局方式允许你将多个控件或窗口部件堆叠在一起,但每次只显示其中一个。这对于需要动态切换界面的应用程序特别有用。
举个简单的例子,下图中的界面就使用了 QStackedLayout 布局管理器:
【解释说明】
- 整个窗口被一分为二,左侧是 QListWidget 列表控件,右侧是 QStackedLayout 布局管理器。QStackedLayout 中包含 QPushButonn、QLabel 和 QLineEdit 这 3 个控件,但每次只能 3 个控件中的一个。
常用方法
成员方法 | 功 能 |
---|---|
int QStackedLayout::addWidget(QWidget *widget) | 将 widget 控件添加到 QStackedLayout 控件中。 |
int QStackedLayout::insertWidget(int index, QWidget *widget) | 将 widget 控件插入到 QStackedLayout 控件指定的位置处。 |
信号函数 | 功 能 |
void QStackedLayout::currentChanged(int index) | 切换当前显示的控件时,会触发此信号,index 为显示的新控件的索引。 |
void QStackedLayout::widgetRemoved(int index) | 移除某个控件时,会触发此信号,index 为被移除控件的索引。 |
槽函数 | 功 能 |
void setCurrentIndex(int index) | 将第 index 个控件作为要显示的控件。 |
void QStackedLayout::setCurrentWidget(QWidget *widget) | 设置 widget 作为当前要实现的控件。注意,必须保证 widget 存储在 QStackedLayout 控件中。 |
(六)Spacer
使⽤布局管理器的时候,可能需要在控件之间,添加⼀段空⽩.就可以使⽤ QSpacerItem 来表示.
核心属性
属性 | 说明 |
width | 宽度 |
height | ⾼度 |
hData | ⽔平⽅向的sizePolicy • QSizePolicy::Ignored :忽略控件的尺⼨,不对布局产⽣影响。 • QSizePolicy::Minimum :控件的最⼩尺⼨为固定值,布局时不会超过该值。 • QSizePolicy::Maximum :控件的最⼤尺⼨为固定值,布局时不会⼩于该值。 • QSizePolicy::Preferred :控件的理想尺⼨为固定值,布局时会尽量接近。 值。 • QSizePolicy::Expanding :控件的尺⼨可以根据空间调整,尽可能占据更多空 间。 • QSizePolicy::Shrinking :控件的尺⼨可以根据空间调整,尽可能缩⼩以适应 空间。 |
vData | 垂直⽅向的sizePolicy 选项同上. |
代码示例:创建⼀组左右排列的按钮.
1)在界⾯上创建⼀个 QVBoxLayout ,并添加两个按钮.
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");
layout->addWidget(btn1);
layout->addWidget(btn2);
}
2)直接运行程序,可以看到两个按钮是紧挨着的.
3)在两个按钮中间添加⼀个spacer
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);
}
4)运行程序,观察代码效果.可以看到两个按钮之间已经存在了间隔了.
- 调整QSpacerItem不同的尺⼨,即可看到不同的间距.
其次在Qt Designer中,也可以直接给界⾯上添加spacer.
总结
Qt布局管理器是Qt框架中用于自动调整和管理界面组件位置和大小的重要工具。以下是关于Qt布局管理器的小结:
- 作用与功能:
- 解决组件位置和大小无法自适应父窗口变化的问题。
- 自动调整控件的位置,包括控件之间的间距、对齐等。
- 当用户调整窗口大小时,位于布局管理器内的控件也会随之调整大小,保持界面的美观。
- 无需手动调整每个控件的位置和大小,简化界面设计流程。
- 核心类与继承:
QLayout
是Qt布局管理器的抽象基类。- Qt提供了多种继承自
QLayout
的布局管理器类,如水平布局(QHBoxLayout
)、垂直布局(QVBoxLayout
)、网格布局(QGridLayout
)和表单布局(QFormLayout
)等。
- 优势:
- 自适应窗口大小和屏幕分辨率:Qt布局管理器能够自动调整控件的位置和大小,以适应不同的窗口大小和屏幕分辨率,确保应用程序在不同设备上都能良好显示。
- 简化界面设计:布局管理器使得控件的排列和布局变得更加简单和直观,开发者可以更快地完成用户界面的设计。
- 管理控件之间的关系:布局管理器可以管理控件之间的关系,如控件的对齐方式、间距等,使界面的设计更加协调和美观。
- 使用方法:
- 在Qt Designer中,可以通过拖拽布局管理器到界面中,然后向其中添加控件来创建布局。
- 在代码中,可以使用布局管理器的构造函数和成员函数来创建和管理布局。例如,可以使用
addWidget()
函数向布局中添加控件,使用setSpacing()
函数设置控件之间的间距等。
总之,Qt布局管理器是Qt框架中用于创建和维护良好用户界面的重要工具。通过合理使用布局管理器,可以大大提高应用程序的用户体验。