En esta página

Ejemplo de disposición de flujo

Muestra cómo organizar los widgets para diferentes tamaños de ventana.

Flow Layout implementa un diseño que maneja diferentes tamaños de ventana. La colocación de los widgets cambia dependiendo del ancho de la ventana de la aplicación.

Captura de pantalla del ejemplo de esquema de flujo

La clase Flowlayout utiliza principalmente QLayout y QWidgetItem, mientras que Window utiliza QWidget y QLabel.

Para más información, visita la página de Gestión de Layouts.

Ejecutar el ejemplo

Para ejecutar el ejemplo desde Qt Creatorabra el modo Welcome y seleccione el ejemplo de Examples. Para más información, consulte Qt Creator: Tutorial: Construir y ejecutar.

Definición de la Clase FlowLayout

La clase FlowLayout hereda de QLayout. Es una clase de layout personalizada que ordena sus widgets hijos horizontal y verticalmente.

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;
};

Reimplementamos funciones heredadas de QLayout. Estas funciones añaden elementos al layout y manejan su orientación y geometría.

También declaramos dos métodos privados, doLayout() y smartSpacing(). doLayout() coloca los elementos del layout, mientras que la función smartSpacing() calcula el espacio entre ellos.

Implementación de la clase FlowLayout

Empezamos por el constructor:

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

En el constructor llamamos a setContentsMargins() para establecer el margen izquierdo, superior, derecho e inferior. Por defecto, QLayout utiliza los valores proporcionados por el estilo actual (ver QStyle::PixelMetric).

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

En este ejemplo reimplementamos addItem(), que es una función virtual pura. Cuando se utiliza addItem() la propiedad de los elementos de la maqueta se transfiere a la maqueta, y por lo tanto es responsabilidad de la maqueta borrarlos.

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

addItem() para añadir elementos a la presentación.

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

Implementamos horizontalSpacing() y verticalSpacing() para obtener el espaciado entre los widgets dentro del layout. Si el valor es menor o igual a 0, se utilizará este valor. Si no, se llamará a smartSpacing() para calcular el espaciado.

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;
}

A continuación, implementamos count() para devolver el número de elementos en el diseño. Para navegar por la lista de elementos utilizamos itemAt() y takeAt() para eliminar y devolver elementos de la lista. Si se elimina un elemento, se renumeran los elementos restantes. Las tres funciones son funciones virtuales puras de QLayout.

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

expandingDirections() devuelve los Qt::Orientations en los que el diseño puede hacer uso de más espacio que su sizeHint().

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

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

Para ajustarnos a los widgets cuya altura depende de la anchura, implementamos heightForWidth(). La función hasHeightForWidth() se utiliza para comprobar esta dependencia, y heightForWidth() pasa la anchura a doLayout() que, a su vez, utiliza la anchura como argumento para el rectángulo de disposición, es decir, los límites en los que se disponen los elementos. Este rect no incluye el layout 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() se utiliza normalmente para hacer la disposición real, es decir, calcular la geometría de los elementos de la disposición. En este ejemplo, se llama a doLayout() y se le pasa el rectángulo de disposición.

sizeHint() devuelve el tamaño preferido del diseño y minimumSize() devuelve el tamaño mínimo del diseño.

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() maneja el diseño si horizontalSpacing() o verticalSpacing() no devuelven el valor por defecto. Utiliza getContentsMargins() para calcular el área disponible para los elementos del diseño.

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

A continuación, establece la cantidad adecuada de espacio para cada widget en el diseño, basado en el estilo actual.

        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;
}

La posición de cada elemento en el diseño se calcula sumando la anchura de los elementos y la altura de la línea a las coordenadas x e y iniciales. Esto, a su vez, nos permite averiguar si el siguiente elemento cabe en la línea actual o si debe desplazarse a la siguiente. También encontramos la altura de la línea actual basándonos en la altura de los widgets.

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() está diseñado para obtener el espaciado por defecto de los diseños de nivel superior o de los diseños secundarios. El espaciado por defecto para los diseños de nivel superior, cuando el padre es QWidget, se determinará consultando el estilo. El espaciado predeterminado para los diseños secundarios, cuando el padre es QLayout, se determinará consultando el espaciado del diseño padre.

Proyecto de ejemplo @ 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.