Qt4 中的布局管理
最后修改于 2023 年 10 月 18 日
在本 Qt4 编程教程中,我们将讨论小部件的布局管理。
一个典型的应用程序由各种小部件组成。这些小部件放置在布局中。程序员必须管理应用程序的布局。在 Qt4 中,我们有两个选项
- 绝对定位
- 布局管理器
绝对定位
程序员以像素为单位指定每个小部件的位置和大小。当我们使用绝对定位时,我们必须了解几件事。
- 如果我们调整窗口大小,小部件的大小和位置不会改变。
- 应用程序在各种平台上看起来不同(通常很糟糕)。
- 更改应用程序中的字体可能会破坏布局。
- 如果我们决定更改我们的布局,我们必须完全重做我们的布局,这既乏味又耗时。
可能存在我们可以使用绝对定位的情况。但大多数情况下,在现实世界的程序中,程序员使用布局管理器。
#include <QApplication> #include <QDesktopWidget> #include <QTextEdit> class Absolute : public QWidget { public: Absolute(QWidget *parent = 0); }; Absolute::Absolute(QWidget *parent) : QWidget(parent) { QTextEdit *ledit = new QTextEdit(this); ledit->setGeometry(5, 5, 200, 150); } int main(int argc, char *argv[]) { QApplication app(argc, argv); Absolute window; window.setWindowTitle("Absolute"); window.show(); return app.exec(); }
setGeometry
方法用于以绝对坐标定位窗口中的小部件。
QTextEdit *edit = new QTextEdit(this); edit->setGeometry(5, 5, 200, 150);
我们创建一个 QTextEdit
小部件并手动定位它。 setGeometry
方法做了两件事:它将小部件定位到绝对坐标并调整小部件的大小。


QVBoxLayout
QVBoxLayout
类垂直排列小部件。使用 addWidget
方法将小部件添加到布局中。
#pragma once #include <QWidget> class VerticalBox : public QWidget { public: VerticalBox(QWidget *parent = 0); };
头文件。
#include "verticalbox.h" #include <QVBoxLayout> #include <QPushButton> VerticalBox::VerticalBox(QWidget *parent) : QWidget(parent) { QVBoxLayout *vbox = new QVBoxLayout(this); vbox->setSpacing(1); QPushButton *settings = new QPushButton("Settings", this); settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QPushButton *accounts = new QPushButton("Accounts", this); accounts->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QPushButton *loans = new QPushButton("Loans", this); loans->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QPushButton *cash = new QPushButton("Cash", this); cash->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QPushButton *debts = new QPushButton("Debts", this); debts->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); vbox->addWidget(settings); vbox->addWidget(accounts); vbox->addWidget(loans); vbox->addWidget(cash); vbox->addWidget(debts); setLayout(vbox); }
在我们的示例中,我们有一个垂直布局管理器。我们在其中放入了五个按钮。我们使所有按钮都可以在两个方向上扩展。
QVBoxLayout *vbox = new QVBoxLayout(this); vbox->setSpacing(1);
我们创建 QVBoxLayout
并在子小部件之间设置 1 像素的间距。
QPushButton *settings = new QPushButton("Settings", this); settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
我们创建一个按钮并为其设置大小策略。子小部件由布局管理器管理。默认情况下,按钮水平展开并且垂直具有固定大小。如果我们要更改它,我们需要设置新的大小策略。在我们的例子中,按钮可以在两个方向上扩展。
vbox->addWidget(settings); vbox->addWidget(accounts); ...
我们使用 addWidget
方法将子小部件添加到布局管理器中。
setLayout(vbox);
我们为窗口设置 QVBoxLayout
管理器。
#include "verticalbox.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication app(argc, argv); VerticalBox window; window.resize(240, 230); window.setWindowTitle("VerticalBox"); window.show(); return app.exec(); }
主文件。

按钮
在下面的示例中,我们在窗口的客户区显示两个按钮。它们将位于窗口的右下角。
#pragma once #include <QWidget> #include <QPushButton> class Buttons : public QWidget { public: Buttons(QWidget *parent = 0); private: QPushButton *okBtn; QPushButton *applyBtn; };
头文件。
#include "buttons.h" #include <QVBoxLayout> #include <QHBoxLayout> Buttons::Buttons(QWidget *parent) : QWidget(parent) { QVBoxLayout *vbox = new QVBoxLayout(this); QHBoxLayout *hbox = new QHBoxLayout(); okBtn = new QPushButton("OK", this); applyBtn = new QPushButton("Apply", this); hbox->addWidget(okBtn, 1, Qt::AlignRight); hbox->addWidget(applyBtn, 0); vbox->addStretch(1); vbox->addLayout(hbox); }
假设我们想在窗口的右下角有两个按钮。
QVBoxLayout *vbox = new QVBoxLayout(this); QHBoxLayout *hbox = new QHBoxLayout();
我们创建两个框布局管理器:一个垂直和一个水平框布局管理器。
okBtn = new QPushButton("OK", this); applyBtn = new QPushButton("Apply", this);
我们创建两个推送按钮。
hbox->addWidget(okBtn, 1, Qt::AlignRight); hbox->addWidget(applyBtn, 0);
按钮放置在水平布局管理器中。使用 addWidget
方法。这些按钮右对齐。第一个参数是子小部件。第二个参数是拉伸因子,最后一个参数是对齐方式。通过将 OK 按钮的拉伸因子设置为 1,我们为它从左侧到窗口右侧提供了空间。小部件不会扩展到分配给它的所有空间。最后,Qt::AlignRight
常量将小部件与分配空间的右侧对齐。
vbox->addStretch(1); vbox->addLayout(hbox);
我们通过调用 addStretch
方法在垂直框中放置一个空的、可扩展的空间。然后我们将水平框布局添加到垂直框布局。
#include <QApplication> #include "buttons.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Buttons window; window.resize(290, 170); window.setWindowTitle("Buttons"); window.show(); return app.exec(); }
主文件。

嵌套布局
以下示例的想法是表明可以组合布局管理器。通过组合甚至简单的布局,我们可以创建复杂的对话框或窗口。要嵌套布局,我们使用 addLayout
方法。
#pragma once #include <QWidget> class Layouts : public QWidget { public: Layouts(QWidget *parent = 0); };
头文件。
#include <QVBoxLayout> #include <QPushButton> #include <QListWidget> #include "layouts.h" Layouts::Layouts(QWidget *parent) : QWidget(parent) { QVBoxLayout *vbox = new QVBoxLayout(); QHBoxLayout *hbox = new QHBoxLayout(this); QListWidget *lw = new QListWidget(this); lw->addItem("The Omen"); lw->addItem("The Exorcist"); lw->addItem("Notes on a scandal"); lw->addItem("Fargo"); lw->addItem("Capote"); QPushButton *add = new QPushButton("Add", this); QPushButton *rename = new QPushButton("Rename", this); QPushButton *remove = new QPushButton("Remove", this); QPushButton *removeall = new QPushButton("Remove All", this); vbox->setSpacing(3); vbox->addStretch(1); vbox->addWidget(add); vbox->addWidget(rename); vbox->addWidget(remove); vbox->addWidget(removeall); vbox->addStretch(1); hbox->addWidget(lw); hbox->addSpacing(15); hbox->addLayout(vbox); setLayout(hbox); }
在示例中,我们创建一个窗口,该窗口由四个按钮和一个列表小部件组成。按钮分组在一个垂直列中,并放置在列表小部件的右侧。如果我们调整窗口大小,列表小部件也会被调整大小。
QVBoxLayout *vbox = new QVBoxLayout();
QVBoxLayout
将成为按钮的列。
QHBoxLayout *hbox = new QHBoxLayout(this);
QHBoxLayout
将是小部件的基本布局。
QListWidget *lw = new QListWidget(this); lw->addItem("The Omen"); lw->addItem("The Exorcist"); lw->addItem("Notes on a scandal"); lw->addItem("Fargo"); lw->addItem("Capote");
创建 QListWidget
。
QPushButton *add = new QPushButton("Add", this); QPushButton *rename = new QPushButton("Rename", this); QPushButton *remove = new QPushButton("Remove", this); QPushButton *removeall = new QPushButton("Remove All", this);
在这里,我们创建了四个按钮。
vbox->setSpacing(3); vbox->addStretch(1); vbox->addWidget(add); vbox->addWidget(rename); vbox->addWidget(remove); vbox->addWidget(removeall); vbox->addStretch(1);
创建包含四个按钮的垂直框。我们在按钮之间留了一些小空间。请注意,我们将拉伸因子添加到垂直框的顶部和底部。这样按钮垂直居中。
hbox->addWidget(lw); hbox->addSpacing(15); hbox->addLayout(vbox);
列表小部件和按钮的垂直框放置在水平框布局中。 addLayout
方法用于将一个布局添加到另一个布局。
setLayout(hbox);
我们为父窗口设置基本布局。
#include <QApplication> #include "layouts.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Layouts window; window.setWindowTitle("Layouts"); window.show(); return app.exec(); }
主文件。

QFormLayout
QFormLayout
是一个简单的布局管理器,用于管理输入小部件及其关联标签的表单。它以两列表单的形式布置其子项。左列由标签组成,右列由输入小部件组成,如 QLineEdit
或 QSpinBox
。
#pragma once #include <QWidget> class FormEx : public QWidget { public: FormEx(QWidget *parent = 0); };
这是头文件。
#include "form.h" #include <QFormLayout> #include <QLabel> #include <QLineEdit> FormEx::FormEx(QWidget *parent) : QWidget(parent) { QLineEdit *nameEdit = new QLineEdit(this); QLineEdit *addrEdit = new QLineEdit(this); QLineEdit *occpEdit = new QLineEdit(this); QFormLayout *formLayout = new QFormLayout; formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter); formLayout->addRow("Name:", nameEdit); formLayout->addRow("Email:", addrEdit); formLayout->addRow("Age:", occpEdit); setLayout(formLayout); }
该示例创建一个由三个标签和三个行编辑组成的表单。
QFormLayout *formLayout = new QFormLayout;
创建 QFormLayout
的一个实例。
formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);
使用 setLabelAlignment
方法,我们设置标签小部件的对齐方式。
formLayout->addRow("Name:", nameEdit);
addRow
方法使用给定的标签和输入小部件向表单布局的底部添加新行。
#include <QApplication> #include "form.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); FormEx window; window.setWindowTitle("Form example"); window.show(); return app.exec(); }
主文件。

QGridLayout
QGridLayout
将其小部件放置在网格中。它是一个强大的布局管理器。
#pragma once #include <QWidget> class Calculator : public QWidget { public: Calculator(QWidget *parent = 0); };
这是头文件。
#include <QGridLayout> #include <QPushButton> #include "calculator.h" Calculator::Calculator(QWidget *parent) : QWidget(parent) { QGridLayout *grid = new QGridLayout(this); grid->setSpacing(2); QList<QString> values({ "7", "8", "9", "/", "4", "5", "6", "*", "1", "2", "3", "-", "0", ".", "=", "+" }); int pos = 0; for (int i=0; i<4; i++) { for (int j=0; j<4; j++) { QPushButton *btn = new QPushButton(values[pos], this); btn->setFixedSize(40, 40); grid->addWidget(btn, i, j); pos++; } } setLayout(grid); }
我们创建一个计算器的框架。
QGridLayout *grid = new QGridLayout(this); grid->setSpacing(2);
我们创建网格布局并在子小部件之间设置 2 像素的间距。
QList<QString> values({ "7", "8", "9", "/", "4", "5", "6", "*", "1", "2", "3", "-", "0", ".", "=", "+" });
这些是显示在按钮上的字符。
for (int i=0; i<4; i++) { for (int j=0; j<4; j++) { QPushButton *btn = new QPushButton(values[pos], this); btn->setFixedSize(40, 40); grid->addWidget(btn, i, j); pos++; } }
我们将十六个小部件放置在网格布局中。每个按钮将具有固定大小。
#include <QApplication> #include "calculator.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Calculator window; window.move(300, 300); window.setWindowTitle("Calculator"); window.show(); return app.exec(); }
这是主文件。

回顾
在本章的下一个示例中,我们将使用 QGridLayout
管理器创建一个更复杂的窗口。
#pragma once #include <QWidget> class Review : public QWidget { public: Review(QWidget *parent = 0); };
头文件。
#include "review.h" #include <QGridLayout> #include <QLabel> #include <QLineEdit> #include <QTextEdit> Review::Review(QWidget *parent) : QWidget(parent) { QGridLayout *grid = new QGridLayout(this); grid->setVerticalSpacing(15); grid->setHorizontalSpacing(10); QLabel *title = new QLabel("Title:", this); grid->addWidget(title, 0, 0, 1, 1); title->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLineEdit *edt1 = new QLineEdit(this); grid->addWidget(edt1, 0, 1, 1, 1); QLabel *author = new QLabel("Author:", this); grid->addWidget(author, 1, 0, 1, 1); author->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLineEdit *edt2 = new QLineEdit(this); grid->addWidget(edt2, 1, 1, 1, 1); QLabel *review = new QLabel("Review:", this); grid->addWidget(review, 2, 0, 1, 1); review->setAlignment(Qt::AlignRight | Qt::AlignTop); QTextEdit *te = new QTextEdit(this); grid->addWidget(te, 2, 1, 3, 1); setLayout(grid); }
该代码创建一个窗口,该窗口可用于输入作者、标题和书籍评论。
QGridLayout *grid = new QGridLayout(this);
创建 QGridLayout
管理器。
grid->setVerticalSpacing(15); grid->setHorizontalSpacing(10);
我们使用 setVerticalSpacing
方法添加垂直间距,并使用 setHorizontalSpacing
方法添加水平间距。
QLabel *title = new QLabel("Title", this); grid->addWidget(title, 0, 0, 1, 1);
这些代码行创建一个标签小部件并将其放置在网格布局中。 addWidget
方法有五个参数。第一个参数是子小部件,在我们的例子中是一个标签。接下来的两个参数是我们在网格中放置标签的行和列。最后,最后的参数是 rowspan 和 colspan。这些参数指定当前小部件将跨越的行数。在我们的例子中,标签将只跨越一列和一行。
title->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
setAlignment
方法将标题标签在其单元格中对齐。水平方向,它右对齐。垂直方向,它居中。
QTextEdit *te = new QTextEdit(this); grid->addWidget(te, 2, 1, 3, 1);
QTextEdit
小部件放置在第三行第二列;它跨越三行和一列。
#include <QApplication> #include "review.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Review window; window.setWindowTitle("Review"); window.show(); return app.exec(); }
主文件。

Qt4 教程的这一部分专门介绍布局管理。