我在夏理当农码 - CSDN: dio夹心小面包

『QT』布局管理器

  |   0 评论   |   29 浏览

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);
}
  • 运行结果为


标题:『QT』布局管理器
作者:orion
地址:http://orionpeng.top/articles/2025/11/25/1764077256321.html

评论

发表评论


取消