基本布局示例

演示如何使用标准布局管理器。

基本布局 展示如何在 Qt 中使用标准布局管理器,包括:QBoxLayoutQGridLayoutQFormLayout

Screenshot of the Basic Layouts example

QBoxLayout 类水平或垂直排列小部件。 QHBoxLayoutQVBoxLayoutQBoxLayout 的便捷子类。 QGridLayout 将小部件布局在单元格中,通过将可用空间分成行和列来布局。另一方面,QFormLayout 在两列表单中设置其子项,左侧为标签,右侧为输入字段。

有关更多信息,请访问布局管理页面。

运行示例

要从 Qt Creator 运行示例,请进入欢迎模式并从示例选择示例。有关更多信息,请访问构建和运行示例

对话框类定义

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog();

private:
    void createMenu();
    void createHorizontalGroupBox();
    void createGridGroupBox();
    void createFormGroupBox();

    enum { NumGridRows = 3, NumButtons = 4 };

    QMenuBar *menuBar;
    QGroupBox *horizontalGroupBox;
    QGroupBox *gridGroupBox;
    QGroupBox *formGroupBox;
    QTextEdit *smallEditor;
    QTextEdit *bigEditor;
    QLabel *labels[NumGridRows];
    QLineEdit *lineEdits[NumGridRows];
    QPushButton *buttons[NumButtons];
    QDialogButtonBox *buttonBox;

    QMenu *fileMenu;
    QAction *exitAction;
};

Dialog 类继承自 QDialog。它是一个自定义小部件,使用几何管理器:QHBoxLayoutQVBoxLayoutQGridLayoutQFormLayout 展示其子小部件。

有四个私有函数来简化类构造函数:createMenu()createHorizontalGroupBox()createGridGroupBox()createFormGroupBox() 函数创建了示例中所使用的多个小部件,以演示布局如何影响它们的外观。

对话框类实现

Dialog::Dialog()
{
    createMenu();
    createHorizontalGroupBox();
    createGridGroupBox();
    createFormGroupBox();

在构造函数中,我们首先使用 createMenu() 函数创建并填充菜单栏,然后使用 createHorizontalGroupBox() 函数创建一个包含四个具有水平布局的按钮的分组框。接下来,我们使用 createGridGroupBox() 函数创建一个包含多个行编辑和一个小文本编辑器的分组框,这些小部件以网格布局显示。最后,我们使用 createFormGroupBox() 函数创建一个包含三个标签和三个输入字段(一个行编辑、一个组合框和一个微调框)的分组框。

    bigEditor = new QTextEdit;
    bigEditor->setPlainText(tr("This widget takes up all the remaining space "
                               "in the top-level layout."));

    buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
                                     | QDialogButtonBox::Cancel);

    connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
    connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);

我们还创建了一个大文本编辑器和对话框按钮框。QDialogButtonBox 类是一个小部件,它以适合当前小部件样式的布局呈现按钮。可以使用 QDialogButtonBox::StandardButtons 枚举作为构造函数的参数指定首选按钮。

注意,在创建小部件时,我们不必指定其父元素。原因是这里创建的所有小部件都将被添加到布局中,当我们把一个小部件添加到布局中时,它将被自动重置为布局所安装的小部件的父元素。

    QVBoxLayout *mainLayout = new QVBoxLayout;

主要布局是一个 QVBoxLayout 对象。 QVBoxLayout 是一个面向垂直方向的框布局的便利类。

一般来说,QBoxLayout 类接收它所获得的空白空间(从父布局或从父小部件),将其分割成一系列盒子,并且使每个管理小部件填充一个盒子。如果 QBoxLayout 的方向是 Qt::Horizontal,则盒子将放置在一排中。如果方向是 Qt::Vertical,则盒子将放置在一列中。对应的便利类分别是 QHBoxLayoutQVBoxLayout

    mainLayout->setMenuBar(menuBar);

当我们调用 QLayout::setMenuBar() 函数时,布局会将提供的菜单栏放置在父小部件的顶部,并在小部件的 内容边距 之外。所有子小部件都放置在菜单栏的底部边缘以下。

    mainLayout->addWidget(horizontalGroupBox);
    mainLayout->addWidget(gridGroupBox);
    mainLayout->addWidget(formGroupBox);
    mainLayout->addWidget(bigEditor);
    mainLayout->addWidget(buttonBox);

我们使用 QBoxLayout::addWidget() 函数将小部件添加到布局的末尾。每个小部件将至少获得其最小大小,最多获得其最大大小。可以在 addWidget() 函数中指定拉伸因子,任何额外的空间将根据这些拉伸因子共享。如果没有指定,小部件的拉伸因子为 0。

    setLayout(scrollLayout);
    setWindowTitle(tr("Basic Layouts"));
}

使用 QWidget::setLayout() 函数将主布局安装到 Dialog 小部件上,布局的所有小部件都会自动重置,使其成为 Dialog 小部件的子元素。

void Dialog::createMenu()
{
    menuBar = new QMenuBar;

    fileMenu = new QMenu(tr("&File"), this);
    exitAction = fileMenu->addAction(tr("E&xit"));
    menuBar->addMenu(fileMenu);

    connect(exitAction, &QAction::triggered, this, &QDialog::accept);
}

在私有函数 createMenu() 中,我们创建一个菜单栏,并添加一个包含 退出 选项的下拉 文件 菜单。

void Dialog::createHorizontalGroupBox()
{
    horizontalGroupBox = new QGroupBox(tr("Horizontal layout"));
    QHBoxLayout *layout = new QHBoxLayout;

    for (int i = 0; i < NumButtons; ++i) {
        buttons[i] = new QPushButton(tr("Button %1").arg(i + 1));
        layout->addWidget(buttons[i]);
    }
    horizontalGroupBox->setLayout(layout);
}

当创建水平分组框时,我们使用 QHBoxLayout 作为内部布局。我们创建想要放入分组框中的按钮,将其添加到布局中,并将布局安装到分组框上。

void Dialog::createGridGroupBox()
{
    gridGroupBox = new QGroupBox(tr("Grid layout"));

createGridGroupBox() 函数中,我们使用一个 QGridLayout 对象,该对象在网格中排列小部件。它接收其父布局或父小部件提供的空间,将其分割成行和列,并将其管理的每个小部件放置在正确的单元格中。

    for (int i = 0; i < NumGridRows; ++i) {
        labels[i] = new QLabel(tr("Line %1:").arg(i + 1));
        lineEdits[i] = new QLineEdit;
        layout->addWidget(labels[i], i + 1, 0);
        layout->addWidget(lineEdits[i], i + 1, 1);
    }

对于网格中的每一行,我们都创建一个标签和一个相关的行编辑,并将它们添加到布局中。与 QBoxLayout 中的对应函数不同的是,QGridLayout::addWidget() 需要指定要放置小部件的网格单元格的行和列。

    smallEditor = new QTextEdit;
    smallEditor->setPlainText(tr("This widget takes up about two thirds of the "
                                 "grid layout."));
    layout->addWidget(smallEditor, 0, 2, 4, 1);

QGridLayout::addWidget() 还可以接受指定单元格将跨越的行数和列数的参数。在这个例子中,我们创建了一个跨越三行一列的小编辑器。

对于 QBoxLayout::addWidget() 和 QGridLayout::addWidget() 函数,还可能添加一个指定小部件对齐方式的最后参数。默认情况下,它将填充整个单元格。但我们也可以通过指定对齐方式为 Qt::AlignRight 来使小部件与右边缘对齐。

    layout->setColumnStretch(1, 10);
    layout->setColumnStretch(2, 20);
    gridGroupBox->setLayout(layout);
}

网格布局中的每一列都有一个拉伸因子。拉伸因子通过使用 QGridLayout::setColumnStretch() 设置,它决定了列将比其必需的最小空间获得多少可用空间。

在本例中,我们设置了第1列和第2列的拉伸因子。拉伸因子相对于此网格中的其他列;具有更高拉伸因子的列将获得更多可用空间。因此,在我们的网格布局中,第2列将比第1列获得更多可用空间,而第0列由于拉伸因子为0(默认值)将不会增长。

列和行的行为相同;行也有一个等效的拉伸因子,以及一个 QGridLayout::setRowStretch() 函数。

void Dialog::createFormGroupBox()
{
    formGroupBox = new QGroupBox(tr("Form layout"));
    QFormLayout *layout = new QFormLayout;
    layout->addRow(new QLabel(tr("Line 1:")), new QLineEdit);
    layout->addRow(new QLabel(tr("Line 2, long text:")), new QComboBox);
    layout->addRow(new QLabel(tr("Line 3:")), new QSpinBox);
    formGroupBox->setLayout(layout);
}

createFormGroupBox() 函数中,我们使用一个 QFormLayout 将对象整齐地排列成两列 - 名称和字段。有三个 QLabel 对象用于名称,对应三个输入小部件作为字段:一个 QLineEdit,一个 QComboBox 和一个 QSpinBox。与 QBoxLayout::addWidget() 和 QGridLayout::addWidget() 不同,我们使用 QFormLayout::addRow() 将小部件添加到布局中。

示例项目 @ code.qt.io

© 2024 The Qt Company Ltd。本文件中包含的文档贡献是各自所有者的版权。本文件中的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款许可的。Qt 及其相关标志是芬兰和/或世界其他地区的 The Qt Company Ltd 的商标。所有其他商标均为各自所有者的财产。