【Qt】Qt之网格布局

00. 目录

文章目录

01. 概述

QGridLayout:格栅布局,也被称作网格布局(多行多列)。

栅格布局将位于其中的窗口部件放入一个网状的栅格之中。QGridLayout需要将提供给它的空间划分成的行和列,并把每个窗口部件插入并管理到正确的单元格。 栅格布局是这样工作的:

它计算了位于其中的空间,然后将它们合理的划分成若干个行(row)和列(column),并把每个由它管理的窗口部件放置在合适的单元之中,这里所指的单元(cell)即是指由行和列交叉所划分出来的空间。

在栅格布局中,行和列本质上是相同的,只是叫法不同而已。下面将重点讨论列,这些内容当然也适用于行。

在栅格布局中,每个列(以及行)都有一个最小宽度(使用setColumnMinimumWidth()设置)以及一个伸缩因子(使用setColumnStretch()设置)。最小宽度指的是位于该列中的窗口部件的最小的宽度,而伸缩因子决定了该列内的窗口部件能够获得多少空间。

02. 开发环境

Windows系统:Windows10

Qt版本:Qt5.15或者Qt6

03. 常用函数详解

QGridLayout 类将控件放置到网格中布局,它本身会从父窗口或父布局中占据尽可能多的界面空间,然后把自己的空间划分为行和列,再把每个控件塞到设置好的一个或多个单元格中。

QGridLayout 类既有控制行的函数,也有对应控制列的函数。对于列来说,有设置每列的最小宽度的函数:
void setColumnMinimumWidth(int column, int minSize)
如果要设置各个列在窗口变化时拉伸比例不同,可以用如下函数:
void setColumnStretch(int column, int stretch)
每列控件之间可以设置布局的水平间隙:
void setHorizontalSpacing(int spacing)
对于行,也都有类似的函数,只是把英文单词换一下:
void setRowMinimumHeight(int row, int minSize) //设置行最小高度
void setRowStretch(int row, int stretch)       //设置行的伸展因子
void setHorizontalSpacing(int spacing)         //设置行的垂直间隙

如果要添加控件或其他布局器、自定义布局条目,使用如下函数:
void addWidget(QWidget * widget, int row, int column, Qt::Alignment alignment = 0)
void addWidget(QWidget * widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = 0)
void addLayout(QLayout * layout, int row, int column, Qt::Alignment alignment = 0)
void addLayout(QLayout * layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = 0)
void addItem(QLayoutItem * item, int row, int column, int rowSpan = 1, int columnSpan = 1, Qt::Alignment alignment = 0)
函数第一个参数都是要添加的控件、布局器或自定义布局条目,
row 和 column 是左上角起始的单元格坐标,
如果没有指定 rowSpan 和 columnSpan 那么就是 1*1 的唯一单元格,
指定了 rowSpan 和 columnSpan 就会占据 rowSpan * columnSpan 的小矩形,占据连续多行多列单元格。
最后的 alignment 是控件或布局器、布局条目在单元格中的对齐方式,比如水平的左对齐、居中、右对齐,垂直方向顶部对齐、底部对齐、垂直居中等等,具体 的可以查 Qt 帮助文档。Qt 关于对齐方式的枚举常量都是通用的。
通常情况下 QGridLayout 不需要自己添加空白条 QSpacerItem,因为其他功能控件把各自的单元格占据之后,剩下没控件占据的单元格自然就是空的,空的格子默认里面什么都没有,也没有空白条。
如果要获知网格有多少行、有多少列(包括空的格子计数),使用如下函数:
int rowCount() const      //行计数
int columnCount() const   //列计数
如果要获取某个单元格的布局条目,使用:
QLayoutItem * itemAtPosition(int row, int column) const
注意,如果某个格子是全空的,也没有手动添加空白条,那么 itemAtPosition() 返回 NULL 指针。因此使用这个函数必须判断返回值是否为空。

rowCount * columnCount 是总共的单元格计数,但并不是控件或子布局的计数。控件或子布局的计数用重载的虚函数:
virtual int count() const
用 add* 函数添加控件或子布局时,每个控件或子布局都对应一个序号,这个序号与网格坐标是无关的,是由 add* 函数添加顺序决定的。
QGridLayout 提供了根据控件或子布局序号查询单元格位置、分布的函数(但没有反查序号的函数):
void getItemPosition(int index, int * row, int * column, int * rowSpan, int * columnSpan) const
getItemPosition() 函数会填充参数里的四个指针指向的变量,四个指针指向的变量就是 add* 函数里面指定的单元格坐标和分布。
根据控件或子布局的序号获取布局条目的函数为:
virtual QLayoutItem * itemAt(int index) const
根据控件序号可以从 QGridLayout 中移除布局条目:
virtual QLayoutItem * takeAt(int index)
凡是函数返回值为指针的都要判断是否为空指针,因为上面函数的序号如果超出范围,也会返回空指针。涉及到指针的操作一定要细心判断。

得到非空的 QLayoutItem 对象指针之后,就可以从 QLayoutItem 对象里提取实际的控件或布局器、空白条:
QWidget * QLayoutItem::​widget()
QLayout * QLayoutItem::​layout()
QSpacerItem * QLayoutItem::​spacerItem()
另外如果是自己定制的 QLayoutItem 派生类对象,可以把获取的基类对象指针 QLayoutItem * ,通过 dynamic_cast 转成派生类对象指针试试。 注意判断函数返回的指针是否为空,非空指针才能进行下一步操作。    

04. Qt设计师使用网格布局

第一种方式:选中所有需要使用网格布局的控件,然后鼠标右击选择布局,然后再选择网格布局。

第二种方式:选中所有需要使用网格布局的控件,然后在工具栏中选择使用网格布局。
【Qt】Qt之网格布局

05. 使用代码实现网格布局

程序示例一:

#include <QApplication>

#include <QGridLayout>
#include <QPushButton>
#include <QWidget>
#include <QObject>
#include <QDebug>

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    QWidget w;

    //创建布局对象
    QGridLayout *layout = new QGridLayout();

    QPushButton *btn1 = new QPushButton;
    btn1->setText("Test Button 1");
    //设置组件大小可以扩展
    btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn1->setMinimumSize(160, 30);


    QPushButton *btn2 = new QPushButton;
    btn2->setText("Test Button 2");
    //设置组件大小可以扩展
    btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn2->setMinimumSize(160, 30);

    QPushButton *btn3 = new QPushButton;
    btn3->setText("Test Button 3");
    //设置组件大小可以扩展
    btn3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn3->setMinimumSize(160, 30);

    QPushButton *btn4 = new QPushButton;
    btn4->setText("Test Button 4");
    //设置组件大小可以扩展
    btn4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn4->setMinimumSize(160, 30);


    //设置间距
    layout->setSpacing(10);
    //网格不同坐标添加不同的组件
    layout->addWidget(btn1, 0, 0);
    layout->addWidget(btn2, 0, 1);
    layout->addWidget(btn3, 1, 0);
    layout->addWidget(btn4, 1, 1);

    //设置行列比例系数
    layout->setRowStretch(0, 1);
    layout->setRowStretch(1, 3);
    layout->setColumnStretch(0, 1);
    layout->setColumnStretch(1, 3);

    w.setLayout(layout);
    w.show();

    return a.exec();
}

执行结果
【Qt】Qt之网格布局

程序示例二:

#include <QApplication>

#include <QGridLayout>
#include <QPushButton>
#include <QWidget>
#include <QObject>
#include <QDebug>

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    QWidget w;

    //创建布局对象
    QGridLayout *layout = new QGridLayout();

    QPushButton *btn1 = new QPushButton("one");
    QPushButton *btn2 = new QPushButton("two");
    QPushButton *btn3 = new QPushButton("three");
    QPushButton *btn4 = new QPushButton("four");
    QPushButton *btn5 = new QPushButton("five");

    layout->addWidget(btn1, 0, 0);
    layout->addWidget(btn2, 0, 1);
    layout->addWidget(btn3, 1, 0, 1, 2);
    layout->addWidget(btn4, 2, 0);
    layout->addWidget(btn5, 2, 1);


    w.setLayout(layout);
    w.show();

    return a.exec();
}

执行结果
【Qt】Qt之网格布局

程序示例三:

#include <QApplication>

#include <QGridLayout>
#include <QPushButton>
#include <QWidget>
#include <QObject>
#include <QDebug>

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    QWidget w;

    //创建布局对象
    QGridLayout *layout = new QGridLayout();

    QPushButton *btn1 = new QPushButton;
    btn1->setText("Test Button 1");
    //设置组件大小可以扩展
    btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn1->setMinimumSize(160, 30);


    QPushButton *btn2 = new QPushButton;
    btn2->setText("Test Button 2");
    //设置组件大小可以扩展
    btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn2->setMinimumSize(160, 30);

    QPushButton *btn3 = new QPushButton;
    btn3->setText("Test Button 3");
    //设置组件大小可以扩展
    btn3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn3->setMinimumSize(160, 30);

    QPushButton *btn4 = new QPushButton;
    btn4->setText("Test Button 4");
    //设置组件大小可以扩展
    btn4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn4->setMinimumSize(160, 30);


    //设置间距
    layout->setSpacing(10);
    //网格不同坐标添加不同的组件
    //坐标(0, 0)的组件占用两行一列
    layout->addWidget(btn1, 0, 0, 2, 1);
    //坐标(0, 1)的组件占用两行一列
    layout->addWidget(btn2, 0, 1, 2, 1);
    //坐标(2, 0)的组件占用一行两列
    layout->addWidget(btn3, 2, 0, 1, 2);
    //坐标(3, 0)的组件占用一行两列
    layout->addWidget(btn4, 3, 0, 1, 2);


    w.setLayout(layout);
    w.show();

    return a.exec();
}

执行结果
【Qt】Qt之网格布局

程序示例四:

#include <QApplication>

#include <QGridLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QObject>
#include <QDebug>

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    QWidget w;

    //创建布局对象
    QGridLayout *gLayout = new QGridLayout();
    QVBoxLayout *vLayout = new QVBoxLayout();

    QPushButton *btn1 = new QPushButton;
    btn1->setText("Test Button 1");
    //设置组件大小可以扩展
    btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn1->setMinimumSize(160, 30);


    QPushButton *btn2 = new QPushButton;
    btn2->setText("Test Button 2");
    //设置组件大小可以扩展
    btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn2->setMinimumSize(160, 30);

    QPushButton *btn3 = new QPushButton;
    btn3->setText("Test Button 3");
    //设置组件大小可以扩展
    btn3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn3->setMinimumSize(160, 30);

    QPushButton *btn4 = new QPushButton;
    btn4->setText("Test Button 4");
    //设置组件大小可以扩展
    btn4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn4->setMinimumSize(160, 30);

    QPushButton *btn5 = new QPushButton;
    btn5->setText("Test Button 5");
    //设置组件大小可以扩展
    btn5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    //设置最小尺寸
    btn5->setMinimumSize(160, 30);

    gLayout->setSpacing(10);

    //编号为1 2 3的进行网格布局
    gLayout->addWidget(btn1, 0, 0);
    gLayout->addWidget(btn2, 0, 1);
    gLayout->addWidget(btn3, 1, 0);

    //将编号为4 5的按钮添加到垂直布局器中
    vLayout->addWidget(btn4);
    vLayout->addWidget(btn5);

    //布局管理器嵌套
    gLayout->addLayout(vLayout, 1, 1);


    w.setLayout(gLayout);
    w.show();

    return a.exec();
}

执行结果:
【Qt】Qt之网格布局

程序示例五:

#include <QApplication>

#include <QGridLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QObject>
#include <QLabel>
#include <QLineEdit>
#include <QCheckBox>
#include <QDebug>

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    QWidget w;
    // 构建控件 头像、用户名、密码输入框等
    QLabel *pImageLabel = new QLabel;
    QLineEdit *pUserLineEdit = new QLineEdit;
    QLineEdit *pPasswordLineEdit = new QLineEdit;
    QCheckBox *pRememberCheckBox = new QCheckBox;
    QCheckBox *pAutoLoginCheckBox = new QCheckBox;
    QPushButton *pLoginButton = new QPushButton;
    QPushButton *pRegisterButton = new QPushButton;
    QPushButton *pForgotButton = new QPushButton;

    pLoginButton->setFixedHeight(30);
    pUserLineEdit->setFixedWidth(200);

    // 设置头像
    QPixmap pixmap("../image/b.png");
    pImageLabel->setFixedSize(90, 90);
    pImageLabel->setPixmap(pixmap);
    pImageLabel->setScaledContents(true);

    // 设置文本
    pUserLineEdit->setPlaceholderText(QStringLiteral("QQ号码/手机/邮箱"));
    pPasswordLineEdit->setPlaceholderText(QStringLiteral("密码"));
    pPasswordLineEdit->setEchoMode(QLineEdit::Password);
    pRememberCheckBox->setText(QStringLiteral("记住密码"));
    pAutoLoginCheckBox->setText(QStringLiteral("自动登录"));
    pLoginButton->setText(QStringLiteral("登录"));
    pRegisterButton->setText(QStringLiteral("注册账号"));
    pForgotButton->setText(QStringLiteral("找回密码"));

    QGridLayout *pLayout = new QGridLayout();
    // 头像 第0行,第0列开始,占3行1列
    pLayout->addWidget(pImageLabel, 0, 0, 3, 1);
    // 用户名输入框 第0行,第1列开始,占1行2列
    pLayout->addWidget(pUserLineEdit, 0, 1, 1, 2);
    pLayout->addWidget(pRegisterButton, 0, 4);
    // 密码输入框 第1行,第1列开始,占1行2列
    pLayout->addWidget(pPasswordLineEdit, 1, 1, 1, 2);
    pLayout->addWidget(pForgotButton, 1, 4);
    // 记住密码 第2行,第1列开始,占1行1列 水平居左 垂直居中
    pLayout->addWidget(pRememberCheckBox, 2, 1, 1, 1, Qt::AlignLeft | Qt::AlignVCenter);
    // 自动登录 第2行,第2列开始,占1行1列 水平居右 垂直居中
    pLayout->addWidget(pAutoLoginCheckBox, 2, 2, 1, 1, Qt::AlignRight | Qt::AlignVCenter);
    // 登录按钮 第3行,第1列开始,占1行2列
    pLayout->addWidget(pLoginButton, 3, 1, 1, 2);
    // 设置水平间距
    pLayout->setHorizontalSpacing(10);
    // 设置垂直间距
    pLayout->setVerticalSpacing(10);
    // 设置外间距
    pLayout->setContentsMargins(10, 10, 10, 10);
    w.setLayout(pLayout);


    w.show();

    return a.exec();
}


执行结果:
【Qt】Qt之网格布局

06. 附录

6.1 Qt教程汇总
网址:https://dengjin.blog.csdn.net/article/details/115174639

上一篇:QSS-qt样式表


下一篇:QT开发基础