Auf dieser Seite

Beispiel für ein Flow-Layout

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

Das Flow-Layout implementiert ein Layout, das unterschiedliche Fenstergrößen berücksichtigt. Die Platzierung der Widgets ändert sich je nach Breite des Anwendungsfensters.

Screenshot des Beispiels zum Flow-Layout

Die Klasse „Flowlayout“ verwendet hauptsächlich „ QLayout “ und „ QWidgetItem “, während das Fenster „ QWidget “ und „ QLabel “ nutzt.

Weitere Informationen finden Sie auf der Seite „Layout-Verwaltung “.

Ausführen des Beispiels

Sie können das Beispiel wie folgt ausführen:

Definition der Klasse „FlowLayout“

Die Klasse „ FlowLayout “ erbt von „ QLayout “. Es handelt sich um eine benutzerdefinierte Layout-Klasse, die ihre untergeordneten Widgets horizontal und vertikal anordnet.

class FlowLayout : public QLayout
{
public:
    explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
    explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
    ~FlowLayout();

    void addItem(QLayoutItem *item) override;
    int horizontalSpacing() const;
    int verticalSpacing() const;
    Qt::Orientations expandingDirections() const override;
    bool hasHeightForWidth() const override;
    int heightForWidth(int) const override;
    int count() const override;
    QLayoutItem *itemAt(int index) const override;
    QSize minimumSize() const override;
    void setGeometry(const QRect &rect) override;
    QSize sizeHint() const override;
    QLayoutItem *takeAt(int index) override;

private:
    int doLayout(const QRect &rect, bool testOnly) const;
    int smartSpacing(QStyle::PixelMetric pm) const;

    QList<QLayoutItem *> itemList;
    int m_hSpace;
    int m_vSpace;
};

Wir implementieren die von „ QLayout “ geerbten Funktionen neu. Diese Funktionen fügen Elemente zum Layout hinzu und verwalten deren Ausrichtung und Geometrie.

Außerdem deklarieren wir zwei private Methoden: „ doLayout() “ und „ smartSpacing() “. „ doLayout() “ ordnet die Layout-Elemente an, während die Funktion „ smartSpacing() “ den Abstand zwischen ihnen berechnet.

Implementierung der Klasse „FlowLayout“

Zunächst betrachten wir den Konstruktor:

FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
    : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
{
    setContentsMargins(margin, margin, margin, margin);
}

FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
    : m_hSpace(hSpacing), m_vSpace(vSpacing)
{
    setContentsMargins(margin, margin, margin, margin);
}

Im Konstruktor rufen wir ` setContentsMargins() ` auf, um den linken, oberen, rechten und unteren Rand festzulegen. Standardmäßig verwendet ` QLayout ` die vom aktuellen Stil bereitgestellten Werte (siehe ` QStyle::PixelMetric`).

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

In diesem Beispiel implementieren wir „ addItem() “ neu, eine rein virtuelle Funktion. Bei der Verwendung von „ addItem() “ geht das Eigentumsrecht an den Layout-Elementen auf das Layout über, weshalb es Aufgabe des Layouts ist, diese zu löschen.

void FlowLayout::addItem(QLayoutItem *item)
{
    itemList.append(item);
}

addItem() wird implementiert, um Elemente zum Layout hinzuzufügen.

int FlowLayout::horizontalSpacing() const
{
    if (m_hSpace >= 0) {
        return m_hSpace;
    } else {
        return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
    }
}

int FlowLayout::verticalSpacing() const
{
    if (m_vSpace >= 0) {
        return m_vSpace;
    } else {
        return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
    }
}

Wir implementieren ` horizontalSpacing() ` und ` verticalSpacing() `, um den Abstand zwischen den Widgets innerhalb des Layouts zu ermitteln. Ist der Wert kleiner oder gleich 0, wird dieser Wert verwendet. Andernfalls wird ` smartSpacing() ` aufgerufen, um den Abstand zu berechnen.

int FlowLayout::count() const
{
    return itemList.size();
}

QLayoutItem *FlowLayout::itemAt(int index) const
{
    return itemList.value(index);
}

QLayoutItem *FlowLayout::takeAt(int index)
{
    if (index >= 0 && index < itemList.size())
        return itemList.takeAt(index);
    return nullptr;
}

Anschließend implementieren wir ` count() `, um die Anzahl der Elemente im Layout zurückzugeben. Zur Navigation durch die Liste der Elemente verwenden wir ` itemAt() ` und `takeAt()`, um Elemente aus der Liste zu entfernen bzw. zurückzugeben. Wird ein Element entfernt, werden die verbleibenden Elemente neu nummeriert. Alle drei Funktionen sind rein virtuelle Funktionen aus ` QLayout`.

Qt::Orientations FlowLayout::expandingDirections() const
{
    return { };
}

expandingDirections() gibt die „ Qt::Orientation“ zurück, in denen das Layout mehr Platz nutzen kann als seine „ sizeHint() “.

bool FlowLayout::hasHeightForWidth() const
{
    return true;
}

int FlowLayout::heightForWidth(int width) const
{
    int height = doLayout(QRect(0, 0, width, 0), true);
    return height;
}

Um Widgets anzupassen, deren Höhe von der Breite abhängt, implementieren wir ` heightForWidth()`. Die Funktion ` hasHeightForWidth() ` dient dazu, diese Abhängigkeit zu prüfen, und ` heightForWidth() ` übergibt die Breite an ` doLayout() `, das wiederum die Breite als Argument für das Layout-Rechteck verwendet, d. h. die Grenzen, innerhalb derer die Elemente angeordnet werden. Dieses Rechteck enthält nicht den Layout-Rand (`margin()`).

void FlowLayout::setGeometry(const QRect &rect)
{
    QLayout::setGeometry(rect);
    doLayout(rect, false);
}

QSize FlowLayout::sizeHint() const
{
    return minimumSize();
}

QSize FlowLayout::minimumSize() const
{
    QSize size;
    for (const QLayoutItem *item : std::as_const(itemList))
        size = size.expandedTo(item->minimumSize());

    const QMargins margins = contentsMargins();
    size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
    return size;
}

setGeometry() wird normalerweise für das eigentliche Layout verwendet, d. h. zur Berechnung der Geometrie der Layout-Elemente. In diesem Beispiel ruft es ` doLayout() ` auf und übergibt das Layout-Rechteck.

sizeHint() gibt die bevorzugte Größe des Layouts zurück, und ` minimumSize() ` gibt die Mindestgröße des Layouts zurück.

int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
{
    int left, top, right, bottom;
    getContentsMargins(&left, &top, &right, &bottom);
    QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
    int x = effectiveRect.x();
    int y = effectiveRect.y();
    int lineHeight = 0;

doLayout() übernimmt die Layout-Verarbeitung, wenn „ horizontalSpacing() “ oder „ verticalSpacing() “ nicht den Standardwert zurückgeben. Es verwendet „ getContentsMargins() “, um den für die Layout-Elemente verfügbaren Bereich zu berechnen.

    for (QLayoutItem *item : std::as_const(itemList)) {
        const QWidget *wid = item->widget();
        int spaceX = horizontalSpacing();
        if (spaceX == -1)
            spaceX = wid->style()->layoutSpacing(
                QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
        int spaceY = verticalSpacing();
        if (spaceY == -1)
            spaceY = wid->style()->layoutSpacing(
                QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);

Anschließend legt es für jedes Widget im Layout den richtigen Abstand fest, basierend auf dem aktuellen Stil.

        int nextX = x + item->sizeHint().width() + spaceX;
        if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
            x = effectiveRect.x();
            y = y + lineHeight + spaceY;
            nextX = x + item->sizeHint().width() + spaceX;
            lineHeight = 0;
        }

        if (!testOnly)
            item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));

        x = nextX;
        lineHeight = qMax(lineHeight, item->sizeHint().height());
    }
    return y + lineHeight - rect.y() + bottom;
}

Die Position jedes Elements im Layout wird anschließend berechnet, indem die Breite des Elements und die Zeilenhöhe zu den anfänglichen x- und y-Koordinaten addiert werden. Dadurch lässt sich wiederum feststellen, ob das nächste Element in die aktuelle Zeile passt oder ob es in die nächste Zeile verschoben werden muss. Außerdem wird die Höhe der aktuellen Zeile anhand der Höhe der Widgets ermittelt.

int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
{
    QObject *parent = this->parent();
    if (!parent) {
        return -1;
    } else if (parent->isWidgetType()) {
        QWidget *pw = static_cast<QWidget *>(parent);
        return pw->style()->pixelMetric(pm, nullptr, pw);
    } else {
        return static_cast<QLayout *>(parent)->spacing();
    }
}

smartSpacing() ist darauf ausgelegt, den Standardabstand entweder für Layouts der obersten Ebene oder für Unterlayouts zu ermitteln. Der Standardabstand für Layouts der obersten Ebene wird – sofern das übergeordnete Layout ein „ QWidget “ ist – durch Abfrage des Stils bestimmt. Der Standardabstand für Unterlayouts wird – sofern das übergeordnete Layout ein „ QLayout “ ist – durch Abfrage des Abstands des übergeordneten Layouts bestimmt.

Beispielprojekt @ code.qt.io

© 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.