Qt Canvas Painter - Hello Widget Example

Demonstrates the use of QCanvasPainter and QCanvasPainterWidget.

The example implements a QCanvasPainterWidget subclass. One or more instances of this widget can then be added into a QMdiArea inside the QMainWindow.

QCanvasPainterWidget itself derives from QRhiWidget, and is always using accelerated 3D rendering via QRhi.

Subclasses of QCanvasPainterWidget will at minimum want to implement paint(). This example also uses an image, loaded from a PNG file.

class CanvasWidget : public QCanvasPainterWidget
{
public:
    CanvasWidget();
    void initializeResources(QCanvasPainter *p) override;
    void paint(QCanvasPainter *p) override;
    void graphicsResourcesInvalidated() override;

private:
    QCanvasImage m_image;
};

The paint() function can start drawing using the provider QCanvasPainter right away:

void CanvasWidget::paint(QCanvasPainter *p)
{
    const float size = std::min(width(), height());
    const float centerX = width() / 2;
    const float centerY = height() / 2;

    // Paint the background circle
    QCanvasRadialGradient gradient1(centerX, centerY - size * 0.1f, size * 0.6f);
    gradient1.setStartColor(QColor(0x909090));
    gradient1.setEndColor(QColor(0x404040));
    p->beginPath();
    p->circle(QPointF(centerX, centerY), size * 0.46f);
    p->setFillStyle(gradient1);
    p->fill();
    p->setStrokeStyle(QColor(0x202020));
    p->setLineWidth(size * 0.02f);
    p->stroke();

See QCanvasPainter, QCanvasBrush, QCanvasRadialGradient, QCanvasImagePattern, QCanvasImage, and QFont for more information on the features used by this example.

The image is used as a pattern, for filling the heart shape:

    // Paint heart
    QCanvasImagePattern pattern(m_image, centerX, centerY, size * 0.08f, size * 0.05f);
    p->setFillStyle(pattern);

When resources like QCanvasImage and QCanvasOffscreenCanvas are involved, these are managed in initializeResources() and graphicsResourcesInvalidated():

void CanvasWidget::initializeResources(QCanvasPainter *p)
{
    Q_ASSERT(m_image.isNull());
    const auto flags = QCanvasPainter::ImageFlag::Repeat | QCanvasPainter::ImageFlag::GenerateMipmaps;
    m_image = p->addImage(QImage(u":/qt-translucent.png"_s), flags);
}

void CanvasWidget::graphicsResourcesInvalidated()
{
    m_image = {};
}

initializeResources() is merely a convenience. Instead of implementing it, one could also write the following in paint():

if (m_image.isNull())
    m_image = p->addImage(QImage(":/qt-translucent.png"), QCanvasPainter::ImageFlag::Repeat);

This example does not reparent widgets between windows, so graphics resources are not going to be lost. It is nonetheless a good pattern to assign a default, empty object to all QCanvasImage and QCanvasOffscreenCanvas variables in graphicsResourcesInvalidated().

The main() function creates a QMainWindow and QMdiArea. Multiple instances of the CanvasWidget class can be added as sub-windows. Due to hasSharedPainter() defaulting to true, and due to being placed within the same top-level widget, all the painter widgets will share the same QCanvasPainter and the associated rendering infrastructure, instead of creating dedicated ones.

Example project @ 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.