Auf dieser Seite

Layout-Verwaltung

Das Qt-Layout-System bietet eine einfache und leistungsstarke Möglichkeit, untergeordnete Widgets innerhalb eines Widgets automatisch so anzuordnen, dass der verfügbare Platz optimal genutzt wird.

Einführung

Qt enthält eine Reihe von Klassen zur Layoutverwaltung, mit denen beschrieben wird, wie Widgets in der Benutzeroberfläche einer Anwendung angeordnet werden. Diese Layouts positionieren Widgets automatisch neu und passen ihre Größe an, wenn sich der für sie verfügbare Platz ändert. So wird sichergestellt, dass sie konsistent angeordnet sind und die Benutzeroberfläche insgesamt benutzerfreundlich bleibt.

Alle Unterklassen von ` QWidget ` können Layouts zur Verwaltung ihrer untergeordneten Elemente verwenden. Die Funktion ` QWidget::setLayout()` wendet ein Layout auf ein Widget an. Wenn auf diese Weise ein Layout für ein Widget festgelegt wird, übernimmt es die folgenden Aufgaben:

  • Positionierung der untergeordneten Widgets
  • Sinnvolle Standardgrößen für Fenster
  • Sinnvolle Mindestgrößen für Fenster
  • Behandlung von Größenänderungen
  • Automatische Aktualisierungen bei Änderungen des Inhalts:
    • Schriftgröße, Text oder andere Inhalte von untergeordneten Widgets
    • Ein- oder Ausblenden eines untergeordneten Widgets
    • Entfernen von untergeordneten Widgets

Qt-Layout-Klassen

Die Layout-Klassen von Qt wurden für handgeschriebenen C++-Code entwickelt und ermöglichen es, Maße der Einfachheit halber in Pixeln anzugeben, sodass sie leicht verständlich und einfach zu verwenden sind. Auch der Code, der für mit dem „ Qt Widgets -Designer“ erstellte Formulare generiert wird, nutzt die Layout-Klassen. Der „ Qt Widgets -Designer“ ist besonders nützlich, wenn man mit dem Design eines Formulars experimentiert, da er den bei der Entwicklung von Benutzeroberflächen üblicherweise erforderlichen Zyklus aus Kompilieren, Verknüpfen und Ausführen umgeht.

QBoxLayout

Richtet untergeordnete Widgets horizontal oder vertikal aus

QButtonGroup

Container zum Organisieren von Gruppen von Schaltflächen-Widgets

QFormLayout

Verwaltet Formulare aus Eingabe-Widgets und den dazugehörigen Beschriftungen

QGraphicsAnchor

Stellt eine Verankerung zwischen zwei Elementen in einem `QGraphicsAnchorLayout` dar

QGraphicsAnchorLayout

Layout, mit dem Widgets in der Graphics View miteinander verankert werden können

QGridLayout

Ordnet Widgets in einem Raster an

QGroupBox

Gruppenrahmen mit einem Titel

QHBoxLayout

Richtet Widgets horizontal aus

QLayout

Die Basisklasse der Geometrie-Manager

QLayoutItem

Abstraktes Element, das von einem QLayout verwaltet wird

QSizePolicy

Layout-Attribut, das die Regeln für die horizontale und vertikale Größenanpassung beschreibt

QSpacerItem

Leerraum in einem Layout

QStackedLayout

Stapel von Widgets, bei dem jeweils nur ein Widget sichtbar ist

QStackedWidget

Stapel von Widgets, bei dem jeweils nur ein Widget sichtbar ist

QVBoxLayout

Richtet Widgets vertikal aus

QWidgetItem

Layout-Element, das ein Widget darstellt

Horizontale, vertikale, Raster- und Formular-Layouts

Der einfachste Weg, Ihren Widgets ein ansprechendes Layout zu verleihen, ist die Verwendung der integrierten Layout-Manager: ` QHBoxLayout`, ` QVBoxLayout`, ` QGridLayout` und ` QFormLayout`. Diese Klassen erben von ` QLayout`, das wiederum von ` QObject ` (nicht von ` QWidget`) abgeleitet ist. Sie übernehmen die Verwaltung der Geometrie für eine Gruppe von Widgets. Um komplexere Layouts zu erstellen, können Sie Layout-Manager ineinander verschachteln.

  • Ein „ QHBoxLayout “ ordnet Widgets in einer horizontalen Reihe von links nach rechts an (bzw. von rechts nach links bei Sprachen, die von rechts nach links geschrieben werden).

    Fünf Schaltflächen in horizontaler Anordnung

  • Ein „ QVBoxLayout “ ordnet Widgets in einer vertikalen Spalte von oben nach unten an.

    Fünf Schaltflächen in vertikaler Anordnung

  • Ein „ QGridLayout “ ordnet Widgets in einem zweidimensionalen Raster an. Widgets können mehrere Zellen einnehmen.

    Fünf Schaltflächen in Rasteranordnung

  • Ein „ QFormLayout “ ordnet Widgets im zweispaltigen Stil „Beschriftung-Feld“ an.

    Drei Schaltflächen mit Textfeldern im Formularlayout

Anordnung von Widgets im Code

Der folgende Code erstellt ein „ QHBoxLayout “, das die Geometrie von fünf „ QPushButtons “ verwaltet, wie auf dem ersten Screenshot oben dargestellt:

QWidget *window = new QWidget;
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");

QHBoxLayout *layout = new QHBoxLayout(window);
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
layout->addWidget(button4);
layout->addWidget(button5);

window->show();

Der Code für „ QVBoxLayout “ ist identisch, mit Ausnahme der Zeile, in der das Layout erstellt wird. Der Code für „ QGridLayout “ unterscheidet sich geringfügig, da wir die Position des untergeordneten Widgets in Zeile und Spalte angeben müssen:

QWidget *window = new QWidget;
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");

QGridLayout *layout = new QGridLayout(window);
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 0, 1);
layout->addWidget(button3, 1, 0, 1, 2);
layout->addWidget(button4, 2, 0);
layout->addWidget(button5, 2, 1);

window->show();

Das dritte „ QPushButton “ erstreckt sich über zwei Spalten. Dies wird ermöglicht, indem man als fünftes Argument für „ QGridLayout::addWidget()“ den Wert 2 angibt.

QFormLayout Fügt zwei Widgets in einer Zeile hinzu, üblicherweise ein „ QLabel “ und ein „ QLineEdit “, um Formulare zu erstellen. Durch das Hinzufügen eines „ QLabel “ und eines „ QLineEdit “ in derselben Zeile wird das „ QLineEdit “ als „Buddy“ des „ QLabel “ festgelegt. Der folgende Code verwendet das „ QFormLayout “, um drei „ QPushButtons “ und ein entsprechendes „ QLineEdit “ in einer Zeile zu platzieren.

QWidget *window = new QWidget;
QPushButton *button1 = new QPushButton("One");
QLineEdit *lineEdit1 = new QLineEdit();
QPushButton *button2 = new QPushButton("Two");
QLineEdit *lineEdit2 = new QLineEdit();
QPushButton *button3 = new QPushButton("Three");
QLineEdit *lineEdit3 = new QLineEdit();

QFormLayout *layout = new QFormLayout(window);
layout->addRow(button1, lineEdit1);
layout->addRow(button2, lineEdit2);
layout->addRow(button3, lineEdit3);

window->show();

Tipps zur Verwendung von Layouts

Wenn Sie ein Layout verwenden, müssen Sie beim Erstellen der untergeordneten Widgets kein übergeordnetes Widget übergeben. Das Layout ordnet die Widgets automatisch neu zu (mithilfe von ` QWidget::setParent()`), sodass sie Kinder des Widgets sind, auf dem das Layout installiert ist.

Hinweis: Widgets in einem Layout sind Kinder des Widgets, auf dem das Layout installiert ist, nicht des Layouts selbst. Widgets können nur andere Widgets als übergeordnetes Element haben, keine Layouts.

Sie können Layouts mithilfe von ` addLayout() ` in einem Layout verschachteln; das innere Layout wird dann zu einem untergeordneten Element des Layouts, in das es eingefügt wird.

Widgets zu einem Layout hinzufügen

Wenn Sie Widgets zu einem Layout hinzufügen, läuft der Layout-Prozess wie folgt ab:

  1. Allen Widgets wird zunächst ein Platz zugewiesen, der ihren Werten für „ QWidget::sizePolicy()“ und „ QWidget::sizeHint()“ entspricht.
  2. Wenn für eines der Widgets Streckungsfaktoren mit einem Wert größer als Null festgelegt sind, wird ihm Platz proportional zu seinem Streckungsfaktor zugewiesen (siehe unten).
  3. Wenn für eines der Widgets ein Stretch-Faktor von Null festgelegt ist, erhält es nur dann mehr Platz, wenn kein anderes Widget diesen Platz beansprucht. Von diesen Widgets erhalten diejenigen zuerst Platz, für die die Größenrichtlinie „ Expanding “ gilt.
  4. Allen Widgets, denen weniger Platz zugewiesen wurde als ihre Mindestgröße (oder der Hinweis auf die Mindestgröße, falls keine Mindestgröße angegeben ist), wird diese erforderliche Mindestgröße zugewiesen. (Widgets müssen keine Mindestgröße oder keinen Hinweis auf die Mindestgröße haben; in diesem Fall ist der Stretch-Faktor der entscheidende Faktor.)
  5. Allen Widgets, denen mehr Platz zugewiesen wird als ihre maximale Größe beträgt, wird der Platz in Höhe ihrer maximalen Größe zugewiesen, den sie benötigen. (Widgets müssen keine maximale Größe haben; in diesem Fall ist der Stretch-Faktor der entscheidende Faktor.)

Dehnungsfaktoren

Widgets werden normalerweise ohne festgelegten Stretch-Faktor erstellt. Beim Einfügen in ein Layout erhalten die Widgets einen Platzanteil entsprechend ihrer Größe ( QWidget::sizePolicy()) oder ihrem Mindestgrößenhinweis, je nachdem, welcher Wert größer ist. Stretch-Faktoren werden verwendet, um zu ändern, wie viel Platz Widgets im Verhältnis zueinander erhalten.

Wenn wir drei Widgets mithilfe von ` QHBoxLayout ` anordnen, ohne Stretch-Faktoren festzulegen, erhalten wir ein Layout wie dieses:

Drei Widgets in einer Reihe mit gleichmäßigen Abständen

Wenn wir auf jedes Widget Stretch-Faktoren anwenden, werden sie proportional angeordnet (jedoch nie kleiner als ihre Mindestgrößenangabe), z. B.

Drei gestreckte Widgets in einer Reihe

Benutzerdefinierte Widgets in Layouts

Wenn Sie eine eigene Widget-Klasse erstellen, sollten Sie auch deren Layout-Eigenschaften angeben. Verwendet das Widget eines der Qt-Layouts, ist dies bereits geregelt. Verfügt das Widget über keine untergeordneten Widgets oder verwendet es ein manuelles Layout, können Sie das Verhalten des Widgets mithilfe eines oder aller der folgenden Mechanismen ändern:

  • Implementieren Sie die Methode ` QWidget::sizeHint()` neu, um die bevorzugte Größe des Widgets zurückzugeben.
  • Implementieren Sie ` QWidget::minimumSizeHint()` neu, um die kleinste Größe zurückzugeben, die das Widget haben kann.
  • Rufen Sie ` QWidget::setSizePolicy()` auf, um den Platzbedarf des Widgets anzugeben.

Rufen Sie ` QWidget::updateGeometry()` auf, sobald sich der Größenhinweis, der Mindestgrößenhinweis oder die Größenrichtlinie ändert. Dies führt zu einer Neuberechnung des Layouts. Mehrere aufeinanderfolgende Aufrufe von ` QWidget::updateGeometry()` führen nur zu einer einzigen Neuberechnung des Layouts.

Wenn die bevorzugte Höhe Ihres Widgets von seiner tatsächlichen Breite abhängt (z. B. bei einer Beschriftung mit automatischem Wortumbruch), setzen Sie das Flag ` height-for-width ` in der Methode ` size policy ` des Widgets und implementieren Sie die Methode ` QWidget::heightForWidth()` neu.

Auch wenn Sie ` QWidget::heightForWidth()` implementieren, ist es dennoch ratsam, einen sinnvollen `sizeHint()` anzugeben.

Weitere Hinweise zur Implementierung dieser Funktionen finden Sie im Qt Quarterly -Artikel „Trading Height for Width“.

Layout-Probleme

Die Verwendung von Rich Text in einem Label-Widget kann zu Problemen beim Layout des übergeordneten Widgets führen. Diese Probleme entstehen durch die Art und Weise, wie Rich Text von den Layout-Managern von Qt verarbeitet wird, wenn im Label ein Zeilenumbruch erfolgt.

In bestimmten Fällen wird das übergeordnete Layout in den Modus „QLayout::FreeResize“ versetzt, was bedeutet, dass es das Layout seines Inhalts nicht an kleine Fenster anpasst oder sogar verhindert, dass der Benutzer das Fenster so klein macht, dass es nicht mehr nutzbar ist. Dies lässt sich beheben, indem man die problematischen Widgets unterklassifiziert und geeignete Funktionen „ sizeHint()“ und „ minimumSizeHint()“ implementiert.

In manchen Fällen ist es von Bedeutung, wann ein Layout zu einem Widget hinzugefügt wird. Wenn Sie das Widget eines ` QDockWidget ` oder eines ` QScrollArea ` festlegen (mit ` QDockWidget::setWidget()` und ` QScrollArea::setWidget()`), muss das Layout bereits für das Widget festgelegt worden sein. Ist dies nicht der Fall, wird das Widget nicht angezeigt.

Manuelles Layout

Wenn Sie ein einzigartiges, spezielles Layout erstellen möchten, können Sie auch ein benutzerdefiniertes Widget wie oben beschrieben erstellen. Implementieren Sie „ QWidget::resizeEvent()“ neu, um die erforderliche Größenverteilung zu berechnen, und rufen Sie für jedes untergeordnete Element „ setGeometry()“ auf.

Das Widget erhält ein Ereignis vom Typ „ QEvent::LayoutRequest “, wenn das Layout neu berechnet werden muss. Implementieren Sie „ QWidget::event()“ neu, um „ QEvent::LayoutRequest “-Ereignisse zu verarbeiten.

So schreiben Sie einen benutzerdefinierten Layout-Manager

Eine Alternative zum manuellen Layout ist das Erstellen eines eigenen Layout-Managers durch Unterklassenbildung von ` QLayout`. Das Beispiel „Flow Layout“ zeigt, wie dies funktioniert.

Hier stellen wir ein Beispiel im Detail vor. Die Klasse „ CardLayout “ ist vom gleichnamigen Java-Layout-Manager inspiriert. Sie ordnet die Elemente (Widgets oder verschachtelte Layouts) übereinander an, wobei jedes Element durch „ QLayout::spacing()“ versetzt wird.

Um eine eigene Layout-Klasse zu schreiben, müssen Sie Folgendes definieren:

  • Eine Datenstruktur zur Speicherung der vom Layout verwalteten Elemente. Jedes Element ist ein ` QLayoutItem`. In diesem Beispiel verwenden wir ein ` QList `.
  • addItem(), wie Elemente zum Layout hinzugefügt werden.
  • setGeometry(), wie das Layout durchgeführt wird.
  • sizeHint(), die bevorzugte Größe des Layouts.
  • itemAt(), wie man das Layout durchläuft.
  • takeAt(), wie Elemente aus dem Layout entfernt werden.

In den meisten Fällen werden Sie auch die Methode ` minimumSize()` implementieren.

Die Header-Datei (card.h)

#ifndef CARD_H
#define CARD_H

#include <QtWidgets>
#include <QList>

class CardLayout : public QLayout
{
public:
    CardLayout(int spacing): QLayout()
    { setSpacing(spacing); }
    CardLayout(int spacing, QWidget *parent): QLayout(parent)
    { setSpacing(spacing); }
    ~CardLayout();

    void addItem(QLayoutItem *item) override;
    QSize sizeHint() const override;
    QSize minimumSize() const override;
    int count() const override;
    QLayoutItem *itemAt(int) const override;
    QLayoutItem *takeAt(int) override;
    void setGeometry(const QRect &rect) override;

private:
    QList<QLayoutItem *> m_items;
};
#endif

Die Implementierungsdatei (card.cpp)

//#include "card.h"

Zunächst definieren wir count(), um die Anzahl der Elemente in der Liste abzurufen.

int CardLayout::count() const
{
    // QList::size() returns the number of QLayoutItems in m_items
    return m_items.size();
}

Anschließend definieren wir zwei Funktionen, die das Layout durchlaufen: ` itemAt() ` und ` takeAt()`. Diese Funktionen werden intern vom Layout-System verwendet, um das Löschen von Widgets zu verarbeiten. Sie stehen auch Anwendungsentwicklern zur Verfügung.

itemAt() gibt das Element am angegebenen Index zurück. ` takeAt() ` entfernt das Element am angegebenen Index und gibt es zurück. In diesem Fall verwenden wir den Listenindex als Layout-Index. In anderen Fällen, in denen wir eine komplexere Datenstruktur haben, müssen wir möglicherweise mehr Aufwand betreiben, um eine lineare Reihenfolge für die Elemente zu definieren.

QLayoutItem *CardLayout::itemAt(int idx) const
{
    // QList::value() performs index checking, and returns nullptr if we are
    // outside the valid range
    return m_items.value(idx);
}

QLayoutItem *CardLayout::takeAt(int idx)
{
    // QList::take does not do index checking
    return idx >= 0 && idx < m_items.size() ? m_items.takeAt(idx) : 0;
}

addItem() Implementiert die Standard-Platzierungsstrategie für Layout-Elemente. Diese Funktion muss implementiert werden. Sie wird von `QLayout::add()` sowie vom Konstruktor ` QLayout ` verwendet, der ein Layout als übergeordnetes Element übernimmt. Wenn Ihr Layout erweiterte Platzierungsoptionen bietet, für die Parameter erforderlich sind, müssen Sie zusätzliche Zugriffsfunktionen bereitstellen, wie beispielsweise die Überladungen von ` QGridLayout::addItem()`, ` QGridLayout::addWidget()` und ` QGridLayout::addLayout()`, die sich über Zeilen und Spalten erstrecken.

void CardLayout::addItem(QLayoutItem *item)
{
    m_items.append(item);
}

Das Layout übernimmt die Verantwortung für die hinzugefügten Elemente. Da ` QLayoutItem ` nicht von ` QObject` erbt, müssen wir die Elemente manuell löschen. Im Destruktor entfernen wir jedes Element mithilfe von ` takeAt()` aus der Liste und löschen es anschließend.

CardLayout::~CardLayout()
{
     QLayoutItem *item;
     while ((item = takeAt(0)))
         delete item;
}

Die Funktion ` setGeometry() ` führt das Layout tatsächlich durch. Das als Argument übergebene Rechteck enthält ` margin()` nicht. Verwenden Sie gegebenenfalls ` spacing() ` als Abstand zwischen den Elementen.

void CardLayout::setGeometry(const QRect &r)
{
    QLayout::setGeometry(r);

    if (m_items.size() == 0)
        return;

    int w = r.width() - (m_items.count() - 1) * spacing();
    int h = r.height() - (m_items.count() - 1) * spacing();
    int i = 0;
    while (i < m_items.size()) {
        QLayoutItem *o = m_items.at(i);
        QRect geom(r.x() + i * spacing(), r.y() + i * spacing(), w, h);
        o->setGeometry(geom);
        ++i;
    }
}

sizeHint() und „ minimumSize() “ sind in der Umsetzung normalerweise sehr ähnlich. Die von beiden Funktionen zurückgegebenen Größen sollten „ spacing() “ enthalten, jedoch nicht „ margin() “.

QSize CardLayout::sizeHint() const
{
    QSize s(0, 0);
    int n = m_items.count();
    if (n > 0)
        s = QSize(100, 70); //start with a nice default size
    int i = 0;
    while (i < n) {
        QLayoutItem *o = m_items.at(i);
        s = s.expandedTo(o->sizeHint());
        ++i;
    }
    return s + n * QSize(spacing(), spacing());
}

QSize CardLayout::minimumSize() const
{
    QSize s(0, 0);
    int n = m_items.count();
    int i = 0;
    while (i < n) {
        QLayoutItem *o = m_items.at(i);
        s = s.expandedTo(o->minimumSize());
        ++i;
    }
    return s + n * QSize(spacing(), spacing());
}

Weitere Hinweise

  • Dieses benutzerdefinierte Layout berücksichtigt die Höhe nicht bei der Breite.
  • Wir ignorieren ` QLayoutItem::isEmpty()`; das bedeutet, dass das Layout ausgeblendete Widgets als sichtbar behandelt.
  • Bei komplexen Layouts lässt sich die Geschwindigkeit durch das Zwischenspeichern berechneter Werte erheblich steigern. Implementieren Sie in diesem Fall ` QLayoutItem::invalidate()`, um die zwischengespeicherten Daten als „dirty“ zu markieren.
  • Der Aufruf von ` QLayoutItem::sizeHint()` usw. kann rechenintensiv sein. Speichern Sie den Wert daher in einer lokalen Variablen, wenn Sie ihn später innerhalb derselben Funktion erneut benötigen.
  • Sie sollten ` QLayoutItem::setGeometry()` nicht zweimal für dasselbe Element innerhalb derselben Funktion aufrufen. Dieser Aufruf kann sehr rechenintensiv sein, wenn das Element mehrere untergeordnete Widgets hat, da der Layout-Manager jedes Mal ein vollständiges Layout durchführen muss. Berechnen Sie stattdessen die Geometrie und legen Sie diese dann fest. (Dies gilt nicht nur für Layouts; Sie sollten beispielsweise genauso vorgehen, wenn Sie Ihr eigenes `resizeEvent()` implementieren.)

Layout-Beispiele

Viele „ Qt Widgets “-Beispiele verwenden bereits Layouts, es gibt jedoch auch zahlreiche Beispiele, die verschiedene Layouts veranschaulichen.

Calculator Example

Das Beispiel zeigt, wie man mithilfe von Signalen und Slots die Funktionalität eines Taschenrechner-Widgets implementiert und wie man mit QGridLayout untergeordnete Widgets in einem Raster anordnet.

Calendar Widget Example

Das Beispiel „Kalender-Widget“ veranschaulicht die Verwendung von `QCalendarWidget`.

Flow Layout Example

Zeigt, wie Widgets für verschiedene Fenstergrößen angeordnet werden.

Image Composition Example

Zeigt, wie Kompositionsmodi in QPainter funktionieren.

Menus Example

Das Beispiel „Menüs“ demonstriert, wie Menüs in einer Hauptfenster-Anwendung verwendet werden können.

Simple Tree Model Example

Das Beispiel „Einfaches Baummodell“ zeigt, wie ein hierarchisches Modell mit den Standard-Ansichtsklassen von Qt verwendet wird.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.