Auf dieser Seite

Beispiel für grundlegende Grafiklayouts

Veranschaulicht, wie man grundlegende Grafiklayouts erstellt.

Das Beispiel „Grundlegende Grafiklayouts“ zeigt, wie man die Layoutklassen in „ QGraphicsView “ verwendet: QGraphicsLinearLayout und QGraphicsGridLayout. Darüber hinaus wird gezeigt, wie man ein eigenes benutzerdefiniertes Layoutelement schreibt.

Screenshot des Beispiels „Grundlegende Layouts“

Definition der Fensterklasse

Die Klasse „ Window “ ist eine Unterklasse von „ QGraphicsWidget “. Sie verfügt über einen Konstruktor, der ein „ QGraphicsWidget “ parent “ als Parameter verwendet.

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 übergeordnetes Element „ windowLayout “ ist. Als Nächstes erstellen wir ein „ LayoutItem “-Objekt, „ item “, und fügen es mit der Funktion „ addItem()“ zu „ linear “ hinzu. Außerdem versehen wir „ 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 das Element „ linear “ hinzu und
  • einen Stretch-Faktor angeben.
    item = new LayoutItem;
    linear->addItem(item);
    linear->setStretchFactor(item, 3);
    windowLayout->addItem(linear);

Anschließend fügen wir „ linear “ zu „ windowLayout “ hinzu und verschachteln dabei zwei „ QGraphicsLinearLayout “-Objekte. Neben dem „ QGraphicsLinearLayout “ verwenden wir außerdem ein „ QGraphicsGridLayout “-Objekt, „ grid “, bei dem es sich um ein 4×3-Raster handelt, bei dem einige Zellen in andere Zeilen hineinreichen.

Wir erstellen sieben „ LayoutItem “-Objekte und fügen sie mit der Funktion „ addItem()“ in „ grid “ ein, wie im folgenden Codeausschnitt 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 Element, das wir zu „ grid “ hinzufügen, wird in die obere linke 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 Eigenschaften „ maximumHeight()“ und „ minimumHeight()“ jedes Elements werden auf denselben Wert gesetzt, damit sie sich vertikal nicht ausdehnen. Infolgedessen passen diese Elemente vertikal nicht 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. Im Gegensatz zu „ QGridLayout::addItem()“ benötigt „ QGraphicsGridLayout::addItem()“ eine Zeile und eine Spalte als Argumente, um anzugeben, in welcher Zelle das Element positioniert werden soll. Wenn die Argumente „ rowSpan “ und „ columnSpan “ weggelassen werden, werden sie standardmäßig auf 1 gesetzt.

Beachten Sie, dass wir nicht für jedes von uns erstellte „ LayoutItem “ 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 untergeordnet, auf dem das Layout installiert ist.

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

Nachdem wir nun ` grid ` eingerichtet und zu ` windowLayout` hinzugefügt haben, installieren wir ` windowLayout ` mithilfe von ` QGraphicsWidget::setLayout()` auf dem Fensterobjekt und legen den Fenstertitel fest.

Definition der Klasse `LayoutItem`

Die Klasse „ LayoutItem “ ist eine Unterklasse von „ QGraphicsLayoutItem “ und „ QGraphicsItem “. Sie verfügt über einen Konstruktor, einen Destruktor und einige erforderliche Neuimplementierungen. Da sie von „ QGraphicsLayoutItem “ erbt, muss sie {QGraphicsLayoutItem::setGeometry()}{setGeometry()} und {QGraphicsLayoutItem::sizeHint()}{sizeHint()} neu implementieren. Darüber hinaus erbt sie von „ QGraphicsItem “, sodass 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 “ verfügt außerdem über eine private Instanz von „ QPixmap “ und „ m_pix “.

Implementierung der Klasse „LayoutItem“

Im Konstruktor von ` LayoutItem` wird ` m_pix ` instanziiert und das Bild ` block.png ` darin 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 bezüglich ungenutzter 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() ` besteht darin, zunächst das Hintergrundrechteck zu zeichnen und anschließend ein Rechteck um die Pixmap herum zu zeichnen.

    // 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 ihre Größe entspricht der Größe der Layout-Elemente ` geometry()`. Dies ist der Bereich, in dem wir zeichnen.

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

Die Neuimplementierung von ` setGeometry()` ruft einfach die Implementierung der Basisklasse auf. Da dies jedoch das `boundingRect` verändert, müssen wir zusätzlich ` 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 möchten, dass die Größe des Elements kleiner als die der Pixmap ist, müssen wir sicherstellen, dass wir einen Größenhinweis zurückgeben, der größer ist als ` m_pix`. Außerdem fügen wir rundherum etwas zusätzlichen Platz für Ränder hinzu, die wir später zeichnen werden. Alternativ könnten Sie die Pixmap skalieren, um zu verhindern, dass das Element kleiner als die Pixmap wird. Die bevorzugte Größe entspricht dem Mindestgrößenhinweis, während wir den Maximalwert 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

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