Qt布局管理器

1. QVBoxLayout

QVBoxLayout表示垂直布局管理器

1.1 常用属性

属性类型读写性说明取值范围
layoutLeftMarginint读写布局的左侧边距,即布局与父容器左侧边缘之间的距离。通过设置该属性,可以控制布局在父容器中左侧的留白大小。非负整数,单位为像素。值为 0 表示没有边距。
layoutRightMarginint读写布局的右侧边距,即布局与父容器右侧边缘之间的距离。用于控制布局在父容器中右侧的留白大小。非负整数,单位为像素。值为 0 表示没有边距。
layoutTopMarginint读写布局的上方边距,即布局与父容器上侧边缘之间的距离。可调整布局在父容器中上方的留白大小。非负整数,单位为像素。值为 0 表示没有边距。
layoutBottomMarginint读写布局的下方边距,即布局与父容器下侧边缘之间的距离。用于设置布局在父容器中下方的留白大小。非负整数,单位为像素。值为 0 表示没有边距。
layoutSpacingint读写布局中相邻元素之间的间距,即垂直排列的子控件之间的垂直距离。能调整子控件之间的疏密程度。非负整数,单位为像素。值为 0 表示子控件紧密排列。

1.2 例子1,使用代码创建

创建5个按钮,widget.cpp如下

Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    QPushButton* bt3 = new QPushButton("Three");
    QPushButton* bt4 = new QPushButton("Four");
    QPushButton* bt5 = new QPushButton("Five");
    // 创建布局管理器,并将按钮添加进去,如果这里指定了parent为this,就不需要后面的setlayout了
    QVBoxLayout* layout = new QVBoxLayout();
    layout->addWidget(bt1);
    layout->addWidget(bt2);
    layout->addWidget(bt3);
    layout->addWidget(bt4);
    layout->addWidget(bt5);
    this->setLayout(layout); // 将一个布局管理器(QLayout 或其派生类的对象)关联到一个 QWidget 上
}

拖动窗口,按钮的位置和大小也会跟着变化

image-20250211143956199

1.3 例子2,使用Qt Designer

先拖入两个Vertical Layout,之后向里面拖入几个控件

image-20250211153121608

运行程序,发现拖动外部的窗口里面的两个Layout不会跟着变化

image-20250211153232075

事实上,一个widget只能设置一个layout布局,观察widget.ui可以发现这两个layout创建了两个QWidget,所以这两个layout不会跟着外部窗口的变化而变化

image-20250211153409583

2. QHBoxLayout

QHBoxLayout表示水平布局,属性与QVBoxLayout类似

2.1 例子1,基础使用

创建3个按钮,widget.cpp如下

Widget::Widget(QWidget *parent)
    : QWidget(parent)
      , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    QPushButton* bt3 = new QPushButton("Three");
    // 创建布局管理器,并将按钮添加进去
    QHBoxLayout* layout = new QHBoxLayout(this);
    layout->addWidget(bt1);
    layout->addWidget(bt2);
    layout->addWidget(bt3);
}

运行结果如下

image-20250211155656987

2.2 例子2,嵌套使用

如果我们想实现如下的样式,需要嵌套使用这两种布局
image-20250211160259312

widget.cpp如下

Widget::Widget(QWidget *parent)
    : QWidget(parent)
      , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QLineEdit* edit1 = new QLineEdit();
    QLineEdit* edit2 = new QLineEdit();
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    // 垂直布局管理器
    QVBoxLayout* v_layout = new QVBoxLayout(this);
    v_layout->addWidget(edit1);
    v_layout->addWidget(edit2);
    // 水平布局管理器
    QHBoxLayout* h_layout = new QHBoxLayout();
    h_layout->addWidget(bt1);
    h_layout->addWidget(bt2);
    // 将水平布局管理器添加到垂直布局管理器里
    v_layout->addLayout(h_layout);
}

运行结果如下
image-20250211160756791

3. QGridLayout

使用QGridLayout来模拟网格布局的效果。可以达到m*n这种的网格效果

3.1 常用属性

属性类型读写性说明取值范围
layoutLeftMarginint读写布局的左侧边距,即布局与父容器左侧边缘之间的距离。它决定了网格布局在父容器中左侧预留的空白区域大小。非负整数,单位为像素,值为 0 表示没有左侧边距。
layoutRightMarginint读写布局的右侧边距,即布局与父容器右侧边缘之间的距离。用于控制网格布局在父容器中右侧预留的空白区域大小。非负整数,单位为像素,值为 0 表示没有右侧边距。
layoutTopMarginint读写布局的上方边距,即布局与父容器上侧边缘之间的距离。可调整网格布局在父容器中上方预留的空白区域大小。非负整数,单位为像素,值为 0 表示没有上方边距。
layoutBottomMarginint读写布局的下方边距,即布局与父容器下侧边缘之间的距离。用于设置网格布局在父容器中下方预留的空白区域大小。非负整数,单位为像素,值为 0 表示没有下方边距。
layoutHorizontalSpacingint读写相邻元素之间水平方向的间距,即网格中同一行的相邻列的子控件之间的水平距离。它能控制子控件在水平方向上的疏密程度。非负整数,单位为像素,值为 0 表示水平方向上子控件紧密排列。
layoutVerticalSpacingint读写相邻元素之间垂直方向的间距,即网格中同一列的相邻行的子控件之间的垂直距离。可调整子控件在垂直方向上的疏密程度。非负整数,单位为像素,值为 0 表示垂直方向上子控件紧密排列。
layoutRowStretchQList<int>读写行方向的拉伸系数,它是一个整数列表,列表中的每个元素对应网格布局中一行的拉伸系数。拉伸系数决定了在布局空间发生变化时,每一行如何分配额外的空间。包含非负整数的列表,列表长度应与网格布局的行数一致。系数越大,该行在空间分配时获得的额外空间越多。
layoutColumnStretchQList<int>读写列方向的拉伸系数,是一个整数列表,列表中的每个元素对应网格布局中一列的拉伸系数。用于决定在布局空间变化时,每一列如何分配额外的空间。包含非负整数的列表,列表长度应与网格布局的列数一致。系数越大,该列在空间分配时获得的额外空间越多。

3.2 例子1,基础使用

widget.cpp代码如下

Widget::Widget(QWidget *parent)
    : QWidget(parent)
      , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->resize(400, 300);
    // 创建按钮
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    QPushButton* bt3 = new QPushButton("Three");
    QPushButton* bt4 = new QPushButton("Four");
    // 创建布局管理器
    QGridLayout* layout = new QGridLayout();
    this->setLayout(layout);
    layout->addWidget(bt1, 0, 0);
    layout->addWidget(bt2, 0, 1);
    layout->addWidget(bt3, 1, 0);
    layout->addWidget(bt4, 1, 1);
}

成功创建出网格样式

image-20250211165556741

这里的坐标是一个相对位置,比如我们下面设置一个比较夸张的值,bt4并没有跑到屏幕外面,并不会在bt3bt4之间腾出来很大的空间

layout->addWidget(bt1, 0, 0);
layout->addWidget(bt2, 1, 0);
layout->addWidget(bt3, 2, 0);
layout->addWidget(bt4, 10, 0);

image-20250211165853687

3.3 例子2,设置列的拉伸因子

Widget::Widget(QWidget *parent)
    : QWidget(parent)
      , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QGridLayout* layout = new QGridLayout();
    this->setLayout(layout);
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    QPushButton* bt3 = new QPushButton("Three");
    layout->addWidget(bt1, 0, 0);
    layout->addWidget(bt2, 0, 1);
    layout->addWidget(bt3, 0, 2);
    // 设置拉伸系数, 三个按钮的比例为1:2:3
    layout->setColumnStretch(0, 1);
    layout->setColumnStretch(1, 2);
    layout->setColumnStretch(2, 3);
}

image-20250211191035335

如果某列的拉伸因子为0,表示该列的大小不随着窗口的变化而变化。但如果只有一列,它仍然会随着窗口变化而变化

3.4 例子3,设置行的拉伸因子

搞一个3行2列的表格,widget.cpp代码如下

Widget::Widget(QWidget *parent)
    : QWidget(parent)
      , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QGridLayout* layout = new QGridLayout();
    this->setLayout(layout);
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    QPushButton* bt3 = new QPushButton("Three");
    QPushButton* bt4 = new QPushButton("Four");
    QPushButton* bt5 = new QPushButton("Five");
    QPushButton* bt6 = new QPushButton("Six");
    layout->addWidget(bt1, 0, 0);
    layout->addWidget(bt2, 0, 1);
    layout->addWidget(bt3, 1, 0);
    layout->addWidget(bt4, 1, 1);
    layout->addWidget(bt5, 2, 0);
    layout->addWidget(bt6, 2, 1);
    // 设置行元素的宽度比例为1:2:3
    layout->setRowStretch(0, 1);
    layout->setRowStretch(1, 2);
    layout->setRowStretch(2, 3);
}

可以看到,宽度并没有如我们所愿,是1:2:3,而是1:1:1

image-20250211195949227

这是因为QPushButton的默认布局行为中,宽度是固定的,可以通过void QWidget::setSizePolicy(QSizePolicy::Policy horizontal, QSizePolicy::Policy vertical)来设定某一个空间的拉伸策略。下面是QSizePolicy::Policy的一些取值

常量描述
QSizePolicy::Fixed0QWidget::sizeHint()是唯一可接受的大小,因此部件不能增大或缩小。例如,推送按钮的垂直方向。
QSizePolicy::MinimumGrowFlagsizeHint()是最小值,且足够。部件可以扩展,但没有更大的必要。例如,推送按钮的水平方向。 它不能小于sizeHint()提供的大小。
QSizePolicy::MaximumShrinkFlagsizeHint()是最大值。部件可以无损地缩小,如果其他部件需要空间的话。例如,分隔线。 它不能大于sizeHint()提供的大小。
QSizePolicy::PreferredGrowFlag | ShrinkFlagsizeHint()是最佳大小,但部件可以缩小且仍然有用。部件可以扩展,但没有大于sizeHint()的必要。QWidget的默认策略。
QSizePolicy::ExpandingGrowFlag | ShrinkFlag | ExpandFlagsizeHint()是合理的大小,但部件可以缩小且仍然有用。部件可以利用额外空间,因此应尽可能多地获取空间。例如,水平滑块的水平方向。
QSizePolicy::MinimumExpandingGrowFlag | ExpandFlagsizeHint()是最小值,且足够。部件可以利用额外空间,因此应尽可能多地获取空间。例如,水平滑块的水平方向。
QSizePolicy::IgnoredShrinkFlag | GrowFlag | IgnoreFlag忽略sizeHint()。部件将尽可能多地获取空间。

所以代码改为

Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 创建布局和按钮
    QGridLayout* layout = new QGridLayout();
    this->setLayout(layout);
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    QPushButton* bt3 = new QPushButton("Three");
    QPushButton* bt4 = new QPushButton("Four");
    QPushButton* bt5 = new QPushButton("Five");
    QPushButton* bt6 = new QPushButton("Six");
    // 设置按钮的布局行为
    bt1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    bt2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    bt3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    bt4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    bt5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    bt6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    // 将按钮添加进布局中
    layout->addWidget(bt1, 0, 0);
    layout->addWidget(bt2, 0, 1);
    layout->addWidget(bt3, 1, 0);
    layout->addWidget(bt4, 1, 1);
    layout->addWidget(bt5, 2, 0);
    layout->addWidget(bt6, 2, 1);
    // 设置行元素的宽度比例为1:2:3
    layout->setRowStretch(0, 1);
    layout->setRowStretch(1, 2);
    layout->setRowStretch(2, 3);
}

这样,按钮的宽度就按照1:2:3的比例缩放了

image-20250211200957281

4. QFormLayout

QFormLayout用于实现两列表单的布局

4.1 例子1,简单使用

widget.cpp代码如下

Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->resize(400, 300);
    // 创建表单布局和他的成员
    QFormLayout* layout = new QFormLayout();
    this->setLayout(layout);
    QLabel*    lable_1 = new QLabel("姓名");
    QLabel*    lable_2 = new QLabel("电话");
    QLabel*    lable_3 = new QLabel("住址");
    QLineEdit* edit_1  = new QLineEdit();
    QLineEdit* edit_2  = new QLineEdit();
    QLineEdit* edit_3  = new QLineEdit();
    // 添加一行
    layout->addRow(lable_1, edit_1);
    layout->addRow(lable_2, edit_2);
    layout->addRow(lable_3, edit_3);
}

运行结果如下

image-20250211205006431

5. QSpacerItem

QSpacerItem用于在控件之间,添加一段空白

5.1 例子1,简单使用

widget.cpp代码如下

Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 创建布局和按钮
    QHBoxLayout* layout = new QHBoxLayout();
    this->setLayout(layout);
    QPushButton* bt1 = new QPushButton("One");
    QPushButton* bt2 = new QPushButton("Two");
    // 创建一个QSpacerItem
    QSpacerItem* spacer = new QSpacerItem(100, 20);
    // 添加QSpacerItem
    layout->addSpacerItem(spacer);
    layout->addWidget(bt1);
    layout->addSpacerItem(spacer);
    layout->addWidget(bt2);
    layout->addSpacerItem(spacer);
}

运行结果如下,可以看到,QSpacerItem把两个按钮“撑开“了,就像弹簧一样

image-20250211211539497

### Qt布局管理器的嵌套使用 在 Qt 的 GUI 开发中,`QLayout` 类提供了多种方式来管理和排列窗口小部件。通过嵌套布局管理器可以构建复杂的用户界面结构。以下是关于如何实现布局管理器嵌套使用的具体方法。 #### 创建主布局和子布局 首先需要分别创建主布局和子布局对象。例如,可以通过 `QVBoxLayout` 或 `QHBoxLayout` 来定义不同的方向布局: ```cpp // 主垂直布局 QVBoxLayout* mainLayout = new QVBoxLayout; // 子水平布局 QHBoxLayout* subLayout = new QHBoxLayout; ``` 上述代码片段展示了如何实例化两个不同类型的布局管理器[^1]。 #### 将子布局添加到主布局 为了实现嵌套效果,需调用主布局的 `addLayout()` 方法或将子布局插入特定位置(如使用 `insertLayout()`)。这一步骤允许将一个布局作为另一个布局的一部分进行管理: ```cpp mainLayout->addLayout(subLayout); ``` 此操作会将 `subLayout` 添加为主布局的一个部分,并由其负责安排其中的小部件或其它布局[^2]。 #### 向子布局添加控件 接着可以在子布局中继续添加所需的控件或者进一步嵌入更深层次的布局: ```cpp QLabel* label = new QLabel("Name:"); QLineEdit* lineEdit = new QLineEdit; subLayout->addWidget(label); subLayout->addWidget(lineEdit); ``` 这里演示了向子水平布局加入标签 (`QLabel`) 和输入框 (`QLineEdit`) 的过程[^3]。 #### 设置顶层窗口的最终布局 最后一步是将整个设计好的主布局应用至顶层窗口上,从而完成整体 UI 架构的设计工作: ```cpp this->setLayout(mainLayout); ``` 这段代码表示将之前配置完毕的复杂层次化的布局体系绑定到了当前窗体之上。 以上就是利用 Qt 实现布局管理器之间相互嵌套的基本流程说明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值