Beispiel für grundlegende Grafiklayouts

Zeigt, wie man grundlegende Grafiklayouts erstellt.

Das Beispiel "Grundlegende Grafiklayouts" zeigt, wie die Layout-Klassen in QGraphicsView: QGraphicsLinearLayout und QGraphicsGridLayout verwendet werden. Darüber hinaus wird gezeigt, wie Sie Ihr eigenes benutzerdefiniertes Layout-Element schreiben können.

Screenshot of the Basic Layouts Example

Definition der Fensterklasse

Die Klasse Window ist eine Unterklasse von QGraphicsWidget. Sie hat einen Konstruktor mit einem QGraphicsWidget parent als Parameter.

class Window : public QGraphicsWidget
{
    Q_OBJECT
public:
    Window(QGraphicsWidget *parent = nullptr);

};

Implementierung der Fensterklasse

Der Konstruktor von Window instanziiert ein QGraphicsLinearLayout Objekt, windowLayout, mit vertikaler Ausrichtung. Wir instanziieren ein weiteres QGraphicsLinearLayout Objekt, linear, dessen Elternteil windowLayout ist. Als nächstes erstellen wir ein LayoutItem Objekt, item und fügen es mit der Funktion addItem() zu linear hinzu. Wir versehen auch item mit einem stretchFactor.

    QGraphicsLinearLayout *windowLayout = new QGraphicsLinearLayout(Qt::Vertical);
    QGraphicsLinearLayout *linear = new QGraphicsLinearLayout(windowLayout);
    LayoutItem *item = new LayoutItem;
    linear->addItem(item);
    linear->setStretchFactor(item, 1);

Wir wiederholen den Vorgang:

  • Erstellen Sie ein neues LayoutItem,
  • fügen Sie das Objekt linear hinzu, und
  • stellen einen Streckungsfaktor bereit.
    item = new LayoutItem;
    linear->addItem(item);
    linear->setStretchFactor(item, 3);
    windowLayout->addItem(linear);

Dann fügen wir linear zu windowLayout hinzu und verschachteln zwei QGraphicsLinearLayout Objekte. Neben dem QGraphicsLinearLayout verwenden wir auch ein QGraphicsGridLayout Objekt, grid, das ein 4x3-Gitter mit einigen Zellen ist, die sich auf andere Zeilen erstrecken.

Wir erstellen sieben LayoutItem Objekte und fügen sie mit der Funktion addItem() in grid ein, wie im folgenden Codeschnipsel gezeigt:

    QGraphicsGridLayout *grid = new QGraphicsGridLayout(windowLayout);
    item = new LayoutItem;
    grid->addItem(item, 0, 0, 4, 1);
    item = new LayoutItem;
    item->setMaximumHeight(item->minimumHeight());
    grid->addItem(item, 0, 1, 2, 1, Qt::AlignVCenter);
    item = new LayoutItem;
    item->setMaximumHeight(item->minimumHeight());
    grid->addItem(item, 2, 1, 2, 1, Qt::AlignVCenter);
    item = new LayoutItem;
    grid->addItem(item, 0, 2);
    item = new LayoutItem;
    grid->addItem(item, 1, 2);
    item = new LayoutItem;
    grid->addItem(item, 2, 2);
    item = new LayoutItem;
    grid->addItem(item, 3, 2);
    windowLayout->addItem(grid);

Das erste Objekt, das wir zu grid hinzufügen, wird in der linken oberen Zelle platziert und erstreckt sich über vier Zeilen. Die nächsten beiden Elemente werden in der zweiten Spalte platziert und erstrecken sich über zwei Zeilen. Die Einträge maximumHeight() und minimumHeight() sind gleich groß, so dass sie sich nicht vertikal ausdehnen. Infolgedessen passen diese Elemente nicht vertikal in ihre Zellen. Daher legen wir mit Qt::AlignVCenter fest, dass sie vertikal in der Mitte der Zelle ausgerichtet werden sollen.

Schließlich wird grid selbst zu windowLayout hinzugefügt. Anders als QGridLayout::addItem() benötigt QGraphicsGridLayout::addItem() eine Zeile und eine Spalte als Argument, um anzugeben, in welcher Zelle das Element positioniert werden soll. Wenn die Argumente rowSpan und columnSpan weggelassen werden, werden sie auf 1 gesetzt.

Beachten Sie, dass wir nicht für jedes LayoutItem, das wir erstellen, ein übergeordnetes Element angeben, da alle diese Elemente zu windowLayout hinzugefügt werden. Wenn wir ein Element zu einem Layout hinzufügen, wird es automatisch dem Widget zugewiesen, auf dem das Layout installiert ist.

    setLayout(windowLayout);
    setWindowTitle(tr("Basic Graphics Layouts Example"));

Nachdem wir nun grid erstellt und zu windowLayout hinzugefügt haben, installieren wir windowLayout mit QGraphicsWidget::setLayout() auf dem Fensterobjekt und setzen den Fenstertitel.

Definition der Klasse LayoutItem

Die Klasse LayoutItem ist eine Unterklasse von QGraphicsLayoutItem und QGraphicsItem. Sie hat einen Konstruktor, einen Destruktor und einige erforderliche Reimplementierungen. Da sie QGraphicsLayoutItem erbt, muss sie {QGraphicsLayoutItem::setGeometry()}{setGeometry()} und {QGraphicsLayoutItem::sizeHint()}{sizeHint()} reimplementieren. Außerdem erbt sie QGraphicsItem, so dass sie {QGraphicsItem::boundingRect()}{boundingRect()} und {QGraphicsItem::paint()}{paint()} neu implementieren muss.

class LayoutItem : public QGraphicsLayoutItem, public QGraphicsItem
{
public:
    LayoutItem(QGraphicsItem *parent = nullptr);

    // Inherited from QGraphicsLayoutItem
    void setGeometry(const QRectF &geom) override;
    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;

    // Inherited from QGraphicsItem
    QRectF boundingRect() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;

private:
    QPixmap m_pix;
};

Die Klasse LayoutItem hat auch eine private Instanz von QPixmap, m_pix.

Implementierung der Klasse LayoutItem

Im Konstruktor von LayoutItem wird m_pix instanziiert und das Bild block.png in die Klasse geladen.

LayoutItem::LayoutItem(QGraphicsItem *parent)
    : QGraphicsLayoutItem(), QGraphicsItem(parent),
      m_pix(QPixmap(QLatin1String(":/images/block.png")))
{
    setGraphicsItem(this);
}

Wir verwenden das Makro Q_UNUSED(), um zu verhindern, dass der Compiler Warnungen über unbenutzte Parameter ausgibt.

void LayoutItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                       QWidget *widget)
{
    Q_UNUSED(widget);
    Q_UNUSED(option);

    QRectF frame(QPointF(0, 0), geometry().size());
    const QSize pmSize = m_pix.size();
    QGradientStops stops;

Die Idee hinter der Funktion paint() ist es, das Hintergrund-Rect zu malen und dann ein Rect um die Pixmap zu malen.

    // paint a background rect (with gradient)
    QLinearGradient gradient(frame.topLeft(), frame.topLeft() + QPointF(200,200));
    stops << QGradientStop(0.0, QColor(60, 60,  60));
    stops << QGradientStop(frame.height() / 2 / frame.height(), QColor(102, 176, 54));

    //stops << QGradientStop(((frame.height() + h)/2 )/frame.height(), QColor(157, 195,  55));
    stops << QGradientStop(1.0, QColor(215, 215, 215));
    gradient.setStops(stops);
    painter->setBrush(QBrush(gradient));
    painter->drawRoundedRect(frame, 10.0, 10.0);

    // paint a rect around the pixmap (with gradient)
    QPointF pixpos = frame.center() - (QPointF(pmSize.width(), pmSize.height()) / 2);
    QRectF innerFrame(pixpos, pmSize);
    innerFrame.adjust(-4, -4, 4, 4);
    gradient.setStart(innerFrame.topLeft());
    gradient.setFinalStop(innerFrame.bottomRight());
    stops.clear();
    stops << QGradientStop(0.0, QColor(215, 255, 200));
    stops << QGradientStop(0.5, QColor(102, 176, 54));
    stops << QGradientStop(1.0, QColor(0, 0,  0));
    gradient.setStops(stops);
    painter->setBrush(QBrush(gradient));
    painter->drawRoundedRect(innerFrame, 10.0, 10.0);
    painter->drawPixmap(pixpos, m_pix);
}

Die Neuimplementierung von boundingRect() setzt die linke obere Ecke auf (0,0), und die Größe des Rects entspricht der Größe der Layoutelemente geometry(). Dies ist der Bereich, in dem wir malen.

QRectF LayoutItem::boundingRect() const
{
    return QRectF(QPointF(0, 0), geometry().size());
}

Die Neuimplementierung von setGeometry() ruft einfach ihre Basisklassenimplementierung auf. Da dies jedoch das BoundingRect ändert, müssen wir auch prepareGeometryChange() aufrufen. Schließlich verschieben wir das Element gemäß geom.topLeft().

void LayoutItem::setGeometry(const QRectF &geom)
{
    prepareGeometryChange();
    QGraphicsLayoutItem::setGeometry(geom);
    setPos(geom.topLeft());
}

Da wir nicht wollen, dass die Größe des Objekts kleiner ist als die Pixmap, müssen wir sicherstellen, dass wir einen Größenhinweis zurückgeben, der größer ist als m_pix. Wir fügen auch etwas zusätzlichen Platz für Ränder hinzu, die wir später malen werden. Alternativ können Sie die Pixmap auch skalieren, um zu verhindern, dass das Element kleiner als die Pixmap wird. Die bevorzugte Größe entspricht dem Hinweis auf die Mindestgröße, während wir die Maximalgröße auf einen großen Wert setzen

QSizeF LayoutItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch (which) {
    case Qt::MinimumSize:
    case Qt::PreferredSize:
        // Do not allow a size smaller than the pixmap with two frames around it.
        return m_pix.size() + QSize(12, 12);
    case Qt::MaximumSize:
        return QSizeF(1000,1000);
    default:
        break;
    }
    return constraint;
}

Beispielprojekt @ code.qt.io

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