Sur cette page

Exemple de mise en page graphique de base

Démontre comment créer une présentation graphique de base.

L'exemple de présentation graphique de base montre comment utiliser les classes de présentation de QGraphicsView: QGraphicsLinearLayout et QGraphicsGridLayout. En outre, il montre comment écrire votre propre élément de présentation personnalisé.

Capture d'écran de l'exemple de présentation de base

Définition de la classe de fenêtre

La classe Window est une sous-classe de QGraphicsWidget. Elle possède un constructeur avec QGraphicsWidget parent comme paramètre.

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

};

Mise en œuvre de la classe Window

Le constructeur de Window instancie un objet QGraphicsLinearLayout, windowLayout, avec une orientation verticale. Nous instançons un autre objet QGraphicsLinearLayout, linear, dont le parent est windowLayout. Ensuite, nous créons un objet LayoutItem, item et l'ajoutons à linear avec la fonction addItem(). Nous fournissons également à item un objet stretchFactor.

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

Nous répétons le processus :

  • créer un nouveau LayoutItem,
  • ajoutons l'élément linear, et
  • et fournissons un facteur d'étirement.
    item = new LayoutItem;
    linear->addItem(item);
    linear->setStretchFactor(item, 3);
    windowLayout->addItem(linear);

Nous ajoutons ensuite linear à windowLayout, en imbriquant deux objets QGraphicsLinearLayout. Outre l'objet QGraphicsLinearLayout, nous utilisons également un objet QGraphicsGridLayout, grid, qui est une grille 4x3 dont certaines cellules s'étendent sur d'autres lignes.

Nous créons sept objets LayoutItem et les plaçons dans grid à l'aide de la fonction addItem(), comme le montre l'extrait de code ci-dessous :

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

Le premier élément que nous ajoutons à grid est placé dans la cellule supérieure gauche, s'étendant sur quatre lignes. Les deux éléments suivants sont placés dans la deuxième colonne et s'étendent sur deux lignes. Les adresses maximumHeight() et minimumHeight() de chaque élément sont définies comme étant égales, de sorte qu'elles ne se développent pas verticalement. Par conséquent, ces éléments ne tiendront pas verticalement dans leurs cellules. Nous spécifions donc qu'ils doivent être alignés verticalement au centre de la cellule à l'aide de Qt::AlignVCenter.

Enfin, grid est lui-même ajouté à windowLayout. Contrairement à QGridLayout::addItem(), QGraphicsGridLayout::addItem() requiert une ligne et une colonne pour son argument, spécifiant ainsi dans quelle cellule l'élément doit être positionné. En outre, si les arguments rowSpan et columnSpan sont omis, ils prendront la valeur 1 par défaut.

Notez que nous ne spécifions pas de parent pour chaque LayoutItem que nous construisons, car tous ces éléments seront ajoutés à windowLayout. Lorsque nous ajoutons un élément à une disposition, il est automatiquement réparti sur le widget sur lequel la disposition est installée.

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

Maintenant que nous avons configuré grid et que nous l'avons ajouté à windowLayout, nous installons windowLayout sur l'objet window à l'aide de QGraphicsWidget::setLayout() et nous définissons le titre de la fenêtre.

Définition de la classe LayoutItem

La classe LayoutItem est une sous-classe de QGraphicsLayoutItem et QGraphicsItem. Elle possède un constructeur, un destructeur et quelques réimplémentations nécessaires. Puisqu'elle hérite de QGraphicsLayoutItem, elle doit réimplémenter {QGraphicsLayoutItem::setGeometry()}{setGeometry()} et {QGraphicsLayoutItem::sizeHint()}{sizeHint()}. En outre, elle hérite de QGraphicsItem, et doit donc réimplémenter {QGraphicsItem::boundingRect()}{boundingRect()} et {QGraphicsItem::paint()}{paint()}.

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

La classe LayoutItem possède également une instance privée de QPixmap, m_pix.

Mise en œuvre de la classe LayoutItem

Dans le constructeur de LayoutItem, m_pix est instancié et l'image block.png y est chargée.

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

Nous utilisons la macro Q_UNUSED() pour éviter que le compilateur ne génère des avertissements concernant les paramètres non utilisés.

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;

L'idée derrière la fonction paint() est de peindre le rectangle d'arrière-plan puis de peindre un rectangle autour de la pixmap.

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

La réimplémentation de boundingRect() placera le coin supérieur gauche à (0,0), et sa taille sera celle des éléments de mise en page geometry(). Il s'agit de la zone à l'intérieur de laquelle nous peignons.

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

La réimplémentation de setGeometry() appelle simplement l'implémentation de la classe de base. Cependant, comme cela modifiera le boundingRect, nous devons également appeler prepareGeometryChange(). Enfin, nous déplaçons l'élément conformément à geom.topLeft().

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

Comme nous ne voulons pas que la taille de l'élément soit inférieure à celle de la pixmap, nous devons nous assurer que nous renvoyons un indice de taille supérieur à m_pix. Nous ajoutons également un peu d'espace supplémentaire pour les bordures que nous peindrons plus tard. Il est également possible de mettre à l'échelle la pixmap pour éviter que l'élément ne devienne plus petit que la pixmap. La taille préférée est la même que l'indice de taille minimale, tandis que nous fixons la taille maximale à une valeur élevée.

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

Exemple de projet @ 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.