Qt5 C++14教程--布局管理

本文介绍了Qt5中用于管理小部件布局的几种方法,包括绝对定位和使用布局管理器如QHBoxLayout,QVBoxLayout,QFormLayout和QGridLayout。绝对定位虽然简单但不灵活,而布局管理器能自动适应窗口大小变化和不同平台。示例代码展示了如何使用这些布局管理器创建各种界面布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Qt5编程教程的这一部分,我们将谈论小部件的布局管理。我们提到QHBoxLayout、QVBoxLayout、QFormLayout和QGridLayout管理器。

一个典型的应用程序由各种小部件组成。这些widget被放置在布局中。一个程序员必须管理应用程序的布局。在Qt5中,我们有两个选择:

  • 绝对定位

  • 布局管理器

绝对定位

在绝对定位中,程序员会指定每个小部件的像素位置和大小。当我们使用绝对定位时,我们必须了解以下几点:

  • 如果我们调整窗口大小,小部件的大小和位置不会改变。

  • 应用程序在不同平台上的外观不同(通常较差)。

  • 更改应用程序中的字体可能会破坏布局。

  • 如果我们决定更改布局,则必须完全重新设计布局,这是繁琐和耗时的。

  • 在某些情况下可能可以使用绝对定位,但在实际的程序中,程序员会使用布局管理器。

absolute.cpp
#include <QApplication>
#include <QDesktopWidget>
#include <QTextEdit>

class Absolute : public QWidget {

 public:
     Absolute(QWidget *parent = nullptr);
};

Absolute::Absolute(QWidget *parent)
    : QWidget(parent) {

  auto *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方法用于以绝对坐标在窗口上定位小部件。

auto *edit = new QTextEdit(this);

ledit->setGeometry(5, 5, 200, 150);

我们创建了一个QTextEdit小部件,并手动定位它。setGeometry方法有两个作用:它将小部件定位到绝对坐标,并调整小部件的大小。

Qt5 QVBoxLayout

QVBoxLayout 类可以将小部件垂直排列。小部件可以使用 addWidget 方法添加到布局中。

vertical_box.h
#pragma once

#include <QWidget>

class VerticalBox : public QWidget {

  public:
    VerticalBox(QWidget *parent = nullptr);
};
The header file.

vertical_box.cpp
#include <QVBoxLayout>
#include <QPushButton>
#include "vertical_box.h"

VerticalBox::VerticalBox(QWidget *parent)
    : QWidget(parent) {

  auto *vbox = new QVBoxLayout(this);
  vbox->setSpacing(1);

  auto *settings = new QPushButton("Settings", this);
  settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

  auto *accounts = new QPushButton("Accounts", this);
  accounts->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

  auto *loans = new QPushButton("Loans", this);
  loans->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

  auto *cash = new QPushButton("Cash", this);
  cash->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

  auto *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);
}

在我们的示例中,我们有一个垂直布局管理器。我们将五个按钮放入其中。我们使所有按钮在两个方向上可扩展。

auto *vbox = new QVBoxLayout(this);vbox->setSpacing(1);

我们创建 QVBoxLayout 并在子小部件之间设置 1 像素的间距。

auto *settings = new QPushButton("Settings", this);

settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

我们创建一个按钮并设置其大小策略。子小部件由布局管理器管理。默认情况下,按钮在水平方向上扩展,垂直方向上具有固定大小。如果我们想要更改它,我们设置新的大小策略。在我们的情况下,按钮可以在两个方向上扩展。

vbox->addWidget(settings);

vbox->addWidget(accounts);

...

我们使用 addWidget 方法将子小部件添加到布局管理器中。

setLayout(vbox);

我们为窗口设置 QVBoxLayout 管理器。

main.cpp
#include <QApplication>
#include "vertical_box.h"

int main(int argc, char *argv[]) {

  QApplication app(argc, argv);

  VerticalBox window;

  window.resize(240, 230);
  window.setWindowTitle("VerticalBox");
  window.show();

  return app.exec();
}

主文件。

按钮

在下面的例子中,我们在窗口的客户区域显示了两个按钮。它们将位于窗口的右下角。

buttons.h
#pragma once

#include <QWidget>
#include <QPushButton>

class Buttons : public QWidget {

  public:
    Buttons(QWidget *parent = nullptr);

  private:
    QPushButton *okBtn;
    QPushButton *applyBtn;
};
Header file.

buttons.cpp
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "buttons.h"

Buttons::Buttons(QWidget *parent)
    : QWidget(parent) {

  auto *vbox = new QVBoxLayout(this);
  auto *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);
}

假设我们想在窗口的右下角有两个按钮。

auto *vbox = new QVBoxLayout(this);

auto *hbox = new QHBoxLayout();

我们创建了两个盒式布局管理器:一个是垂直的,一个是水平的。

okBtn = new QPushButton("OK", this);

applyBtn = new QPushButton("Apply", this);

我们创建了两个按钮。

hbox->addWidget(okBtn, 1, Qt::AlignRight);

hbox->addWidget(applyBtn, 0);

将按钮放置在水平布局管理器中。使用addWidget方法。这些按钮是右对齐的。第一个参数是子小部件。第二个参数是拉伸因子,最后一个参数是对齐方式。通过将拉伸因子设置为1,我们为OK按钮提供了从窗口左侧到右侧的空间。小部件不会扩展到分配给它的所有空间。最后,Qt :: AlignRight常量将小部件对齐到分配的空间的右侧。

vbox->addStretch(1);

vbox->addLayout(hbox);

我们通过调用addStretch方法在垂直盒中放置一个空的可扩展空间。然后将水平盒布局添加到垂直盒布局中。

main.cpp
#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();
}

主文件。

Qt5 嵌套布局

以下示例的想法是展示布局管理器可以组合使用。通过组合甚至是简单的布局,我们可以创建复杂的对话框或窗口。为了嵌套布局,我们使用 addLayout 方法。

nesting.h
#pragma once

#include <QWidget>

class Layouts : public QWidget {

  public:
    Layouts(QWidget *parent = nullptr);
};
This is the header file.

nesting.cpp
#include <QVBoxLayout>
#include <QPushButton>
#include <QListWidget>
#include "nesting.h"

Layouts::Layouts(QWidget *parent)
    : QWidget(parent) {

  auto *vbox = new QVBoxLayout();
  auto *hbox = new QHBoxLayout(this);

  auto *lw = new QListWidget(this);
  lw->addItem("The Omen");
  lw->addItem("The Exorcist");
  lw->addItem("Notes on a scandal");
  lw->addItem("Fargo");
  lw->addItem("Capote");

  auto *add = new QPushButton("Add", this);
  auto *rename = new QPushButton("Rename", this);
  auto *remove = new QPushButton("Remove", this);
  auto *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);
}

在示例中,我们创建了一个窗口,其中包含四个按钮和一个列表小部件。按钮分组成垂直列,并放置在列表小部件的右侧。如果我们调整窗口大小,列表小部件也会被调整大小。

auto *vbox = new QVBoxLayout();

QVBoxLayout 是按钮的列。

auto *hbox = new QHBoxLayout(this);

QHBoxLayout 是小部件的基本布局。

auto *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。

auto *add = new QPushButton("Add", this);

auto *rename = new QPushButton("Rename", this);

auto *remove = new QPushButton("Remove", this);

auto *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);

设置父窗口的基本布局。

main.cpp
#include <QApplication>
#include "nesting.h"

int main(int argc, char *argv[]) {

  QApplication app(argc, argv);

  Layouts window;

  window.setWindowTitle("Layouts");
  window.show();

  return app.exec();
}

Qt5 FormLayout

QFormLayout是一个简单的布局管理器,用于管理输入控件及其关联标签的表单。它将其子控件布置在一个两列的表单中。左列包含标签,右列包含诸如QLineEdit或QSpinBox之类的输入控件。

form.h
#pragma once

#include <QWidget>

class FormEx : public QWidget {

  public:
    FormEx(QWidget *parent = nullptr);
};


form.cpp
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include "form.h"

FormEx::FormEx(QWidget *parent)
    : QWidget(parent) {

  auto *nameEdit = new QLineEdit(this);
  auto *addrEdit = new QLineEdit(this);
  auto *occpEdit = new QLineEdit(this);

  auto *formLayout = new QFormLayout;
  formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);
  formLayout->addRow("Name:", nameEdit);
  formLayout->addRow("Email:", addrEdit);
  formLayout->addRow("Age:", occpEdit);

  setLayout(formLayout);
}

该示例创建了一个由三个标签和三个LineEdit组成的表单。

auto *formLayout = new QFormLayout;

创建了一个QFormLayout的实例。

formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);

通过setLabelAlignment方法设置标签控件的对齐方式。

formLayout->addRow("Name:", nameEdit);

addRow方法在表单布局底部添加一行,包含给定的标签和输入控件。

main.cpp
#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();
}

Qt5 QGridLayout

QGridLayout(网格布局)将窗口部件放置在网格中。它是一个强大的布局管理器。

calculator.h
#pragma once

#include <QWidget>

class Calculator : public QWidget {

  public:
    Calculator(QWidget *parent = nullptr);
};
Header file.

calculator.cpp
#include <QGridLayout>
#include <QPushButton>
#include "calculator.h"

Calculator::Calculator(QWidget *parent)
    : QWidget(parent) {

  auto *grid = new QGridLayout(this);
  grid->setSpacing(2);

  QVector<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++) {

     auto *btn = new QPushButton(values[pos], this);
     btn->setFixedSize(40, 40);
     grid->addWidget(btn, i, j);
     pos++;
   }
  }

  setLayout(grid);
}

我们创建了一个计算器的框架。

auto *grid = new QGridLayout(this);

grid->setSpacing(2);

我们创建了网格布局,并在子窗口部件之间设置了2像素的间距。

QVector<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++) {

    auto *btn = new QPushButton(values[pos], this);
    btn->setFixedSize(40, 40);
    grid->addWidget(btn, i, j);
    pos++;
  }
}

我们将16个窗口部件放入网格布局中。每个按钮都有一个固定的大小。

main.cpp

#include <QApplication>
#include "calculator.h"

int main(int argc, char *argv[]) {

  QApplication app(argc, argv);

  Calculator window;

  window.setWindowTitle("Calculator");
  window.show();

  return app.exec();
}

这是主文件

下面代码创建了一个使用 QGridLayout 管理器的复杂窗口。

review.h
#pragma once

#include <QWidget>

class Review : public QWidget {

  public:
    Review(QWidget *parent = nullptr);
};
Header file.

review.cpp
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include "review.h"

Review::Review(QWidget *parent)
    : QWidget(parent) {

  auto *grid = new QGridLayout(this);
  grid->setVerticalSpacing(15);
  grid->setHorizontalSpacing(10);

  auto *title = new QLabel("Title:", this);
  grid->addWidget(title, 0, 0, 1, 1);
  title->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

  auto *edt1 = new QLineEdit(this);
  grid->addWidget(edt1, 0, 1, 1, 1);

  auto *author = new QLabel("Author:", this);
  grid->addWidget(author, 1, 0, 1, 1);
  author->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

  auto *edt2 = new QLineEdit(this);
  grid->addWidget(edt2, 1, 1, 1, 1);

  auto *review = new QLabel("Review:", this);
  grid->addWidget(review, 2, 0, 1, 1);
  review->setAlignment(Qt::AlignRight | Qt::AlignTop);

  auto *te = new QTextEdit(this);
  grid->addWidget(te, 2, 1, 3, 1);

  setLayout(grid);
}

这段代码创建了一个窗口,可以用于输入一本书的作者、标题和评论。

auto *grid = new QGridLayout(this);

创建了 QGridLayout 管理器。

grid->setVerticalSpacing(15);

grid->setHorizontalSpacing(10);

使用 setVerticalSpacing 方法和 setHorizontalSpacing 方法添加了垂直和水平间距。

auto *title = new QLabel("Title", this);

grid->addWidget(title, 0, 0, 1, 1);

这些代码行创建了一个标签小部件,并将其放置在网格布局中。addWidget 方法有五个参数。第一个参数是子部件,本例中是一个标签。接下来的两个参数是我们放置标签的行和列。最后,最后的参数是 rowspan 和 colspan。这些参数指定当前小部件将跨越多少行。在本例中,标签将跨越一个列和一行。

title->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

setAlignment 方法将标题标签对齐到其单元格中。水平方向上,右对齐。垂直方向上,居中对齐。

auto *te = new QTextEdit(this);

grid->addWidget(te, 2, 1, 3, 1);

QTextEdit 小部件放置在第三行和第二列;它跨越三行和一列。

main.cpp
#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();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值