Basic Drawing Example

The Basic Drawing example shows how to display basic graphics primitives in a variety of styles using the QPainter class.

QPainter performs low-level painting on widgets and other paint devices. The class can draw everything from simple lines to complex shapes like pies and chords. It can also draw aligned text and pixmaps. Normally, it draws in a “natural” coordinate system, but it can in addition do view and world transformation.

Basic Drawing Screenshot

Download this example

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>images/brick.png</file>
    <file>images/qt-logo.png</file>
</qresource>
</RCC>
# Copyright (C) 2013 Riverbank Computing Limited.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations

"""PySide6 port of the widgets/painting/basicdrawing example from Qt v5.x, originating from PyQt"""

from PySide6.QtCore import QPoint, QRect, QSize, Qt, qVersion
from PySide6.QtGui import (QBrush, QConicalGradient, QLinearGradient, QPainter,
                           QPainterPath, QPalette, QPen, QPixmap, QPolygon,
                           QRadialGradient)
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QGridLayout,
                               QLabel, QSpinBox, QWidget)

import basicdrawing_rc  # noqa: F401


class RenderArea(QWidget):
    points = QPolygon([
        QPoint(10, 80),
        QPoint(20, 10),
        QPoint(80, 30),
        QPoint(90, 70)
    ])

    (Line, Points, Polyline, Polygon, Rect, RoundedRect, Ellipse,
     Arc, Chord, Pie, Path, Text, Pixmap) = range(13)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.pen = QPen()
        self.brush = QBrush()
        self.pixmap = QPixmap()

        self.shape = RenderArea.Polygon
        self.antialiased = False
        self.transformed = False
        self.pixmap.load(':/images/qt-logo.png')

        self.setBackgroundRole(QPalette.Base)
        self.setAutoFillBackground(True)

    def minimumSizeHint(self):
        return QSize(100, 100)

    def sizeHint(self):
        return QSize(400, 200)

    def set_shape(self, shape):
        self.shape = shape
        self.update()

    def set_pen(self, pen):
        self.pen = pen
        self.update()

    def set_brush(self, brush):
        self.brush = brush
        self.update()

    def set_antialiased(self, antialiased):
        self.antialiased = antialiased
        self.update()

    def set_transformed(self, transformed):
        self.transformed = transformed
        self.update()

    def paintEvent(self, event):
        rect = QRect(10, 20, 80, 60)

        path = QPainterPath()
        path.moveTo(20, 80)
        path.lineTo(20, 30)
        path.cubicTo(80, 0, 50, 50, 80, 80)

        start_angle = 30 * 16
        arc_length = 120 * 16

        with QPainter(self) as painter:
            painter.setPen(self.pen)
            painter.setBrush(self.brush)
            if self.antialiased:
                painter.setRenderHint(QPainter.RenderHint.Antialiasing)

            for x in range(0, self.width(), 100):
                for y in range(0, self.height(), 100):
                    painter.save()
                    painter.translate(x, y)
                    if self.transformed:
                        painter.translate(50, 50)
                        painter.rotate(60.0)
                        painter.scale(0.6, 0.9)
                        painter.translate(-50, -50)

                    if self.shape == RenderArea.Line:
                        painter.drawLine(rect.bottomLeft(), rect.topRight())
                    elif self.shape == RenderArea.Points:
                        painter.drawPoints(RenderArea.points)
                    elif self.shape == RenderArea.Polyline:
                        painter.drawPolyline(RenderArea.points)
                    elif self.shape == RenderArea.Polygon:
                        painter.drawPolygon(RenderArea.points)
                    elif self.shape == RenderArea.Rect:
                        painter.drawRect(rect)
                    elif self.shape == RenderArea.RoundedRect:
                        painter.drawRoundedRect(rect, 25, 25, Qt.RelativeSize)
                    elif self.shape == RenderArea.Ellipse:
                        painter.drawEllipse(rect)
                    elif self.shape == RenderArea.Arc:
                        painter.drawArc(rect, start_angle, arc_length)
                    elif self.shape == RenderArea.Chord:
                        painter.drawChord(rect, start_angle, arc_length)
                    elif self.shape == RenderArea.Pie:
                        painter.drawPie(rect, start_angle, arc_length)
                    elif self.shape == RenderArea.Path:
                        painter.drawPath(path)
                    elif self.shape == RenderArea.Text:
                        qv = qVersion()
                        painter.drawText(rect, Qt.AlignCenter,
                                         f"PySide 6\nQt {qv}")
                    elif self.shape == RenderArea.Pixmap:
                        painter.drawPixmap(10, 10, self.pixmap)

                    painter.restore()

            painter.setPen(self.palette().dark().color())
            painter.setBrush(Qt.NoBrush)
            painter.drawRect(QRect(0, 0, self.width() - 1, self.height() - 1))


id_role = Qt.ItemDataRole.UserRole


class Window(QWidget):
    def __init__(self):
        super().__init__()

        self._render_area = RenderArea()

        self._shape_combo_box = QComboBox()
        self._shape_combo_box.addItem("Polygon", RenderArea.Polygon)
        self._shape_combo_box.addItem("Rectangle", RenderArea.Rect)
        self._shape_combo_box.addItem("Rounded Rectangle", RenderArea.RoundedRect)
        self._shape_combo_box.addItem("Ellipse", RenderArea.Ellipse)
        self._shape_combo_box.addItem("Pie", RenderArea.Pie)
        self._shape_combo_box.addItem("Chord", RenderArea.Chord)
        self._shape_combo_box.addItem("Path", RenderArea.Path)
        self._shape_combo_box.addItem("Line", RenderArea.Line)
        self._shape_combo_box.addItem("Polyline", RenderArea.Polyline)
        self._shape_combo_box.addItem("Arc", RenderArea.Arc)
        self._shape_combo_box.addItem("Points", RenderArea.Points)
        self._shape_combo_box.addItem("Text", RenderArea.Text)
        self._shape_combo_box.addItem("Pixmap", RenderArea.Pixmap)

        shape_label = QLabel("&Shape:")
        shape_label.setBuddy(self._shape_combo_box)

        self._pen_width_spin_box = QSpinBox()
        self._pen_width_spin_box.setRange(0, 20)
        self._pen_width_spin_box.setSpecialValueText("0 (cosmetic pen)")

        pen_width_label = QLabel("Pen &Width:")
        pen_width_label.setBuddy(self._pen_width_spin_box)

        self._pen_style_combo_box = QComboBox()
        self._pen_style_combo_box.addItem("Solid", Qt.SolidLine)
        self._pen_style_combo_box.addItem("Dash", Qt.DashLine)
        self._pen_style_combo_box.addItem("Dot", Qt.DotLine)
        self._pen_style_combo_box.addItem("Dash Dot", Qt.DashDotLine)
        self._pen_style_combo_box.addItem("Dash Dot Dot", Qt.DashDotDotLine)
        self._pen_style_combo_box.addItem("None", Qt.NoPen)

        pen_style_label = QLabel("&Pen Style:")
        pen_style_label.setBuddy(self._pen_style_combo_box)

        self._pen_cap_combo_box = QComboBox()
        self._pen_cap_combo_box.addItem("Flat", Qt.FlatCap)
        self._pen_cap_combo_box.addItem("Square", Qt.SquareCap)
        self._pen_cap_combo_box.addItem("Round", Qt.RoundCap)

        pen_cap_label = QLabel("Pen &Cap:")
        pen_cap_label.setBuddy(self._pen_cap_combo_box)

        self._pen_join_combo_box = QComboBox()
        self._pen_join_combo_box.addItem("Miter", Qt.MiterJoin)
        self._pen_join_combo_box.addItem("Bevel", Qt.BevelJoin)
        self._pen_join_combo_box.addItem("Round", Qt.RoundJoin)

        pen_join_label = QLabel("Pen &Join:")
        pen_join_label.setBuddy(self._pen_join_combo_box)

        self._brush_style_combo_box = QComboBox()
        self._brush_style_combo_box.addItem("Linear Gradient", Qt.LinearGradientPattern)
        self._brush_style_combo_box.addItem("Radial Gradient", Qt.RadialGradientPattern)
        self._brush_style_combo_box.addItem("Conical Gradient", Qt.ConicalGradientPattern)
        self._brush_style_combo_box.addItem("Texture", Qt.TexturePattern)
        self._brush_style_combo_box.addItem("Solid", Qt.SolidPattern)
        self._brush_style_combo_box.addItem("Horizontal", Qt.HorPattern)
        self._brush_style_combo_box.addItem("Vertical", Qt.VerPattern)
        self._brush_style_combo_box.addItem("Cross", Qt.CrossPattern)
        self._brush_style_combo_box.addItem("Backward Diagonal", Qt.BDiagPattern)
        self._brush_style_combo_box.addItem("Forward Diagonal", Qt.FDiagPattern)
        self._brush_style_combo_box.addItem("Diagonal Cross", Qt.DiagCrossPattern)
        self._brush_style_combo_box.addItem("Dense 1", Qt.Dense1Pattern)
        self._brush_style_combo_box.addItem("Dense 2", Qt.Dense2Pattern)
        self._brush_style_combo_box.addItem("Dense 3", Qt.Dense3Pattern)
        self._brush_style_combo_box.addItem("Dense 4", Qt.Dense4Pattern)
        self._brush_style_combo_box.addItem("Dense 5", Qt.Dense5Pattern)
        self._brush_style_combo_box.addItem("Dense 6", Qt.Dense6Pattern)
        self._brush_style_combo_box.addItem("Dense 7", Qt.Dense7Pattern)
        self._brush_style_combo_box.addItem("None", Qt.NoBrush)

        brush_style_label = QLabel("&Brush Style:")
        brush_style_label.setBuddy(self._brush_style_combo_box)

        other_options_label = QLabel("Other Options:")
        self._antialiasing_check_box = QCheckBox("&Antialiasing")
        self._transformations_check_box = QCheckBox("&Transformations")

        self._shape_combo_box.activated.connect(self.shape_changed)
        self._pen_width_spin_box.valueChanged.connect(self.pen_changed)
        self._pen_style_combo_box.activated.connect(self.pen_changed)
        self._pen_cap_combo_box.activated.connect(self.pen_changed)
        self._pen_join_combo_box.activated.connect(self.pen_changed)
        self._brush_style_combo_box.activated.connect(self.brush_changed)
        self._antialiasing_check_box.toggled.connect(self._render_area.set_antialiased)
        self._transformations_check_box.toggled.connect(self._render_area.set_transformed)

        main_layout = QGridLayout()
        main_layout.setColumnStretch(0, 1)
        main_layout.setColumnStretch(3, 1)
        main_layout.addWidget(self._render_area, 0, 0, 1, 4)
        main_layout.setRowMinimumHeight(1, 6)
        main_layout.addWidget(shape_label, 2, 1, Qt.AlignRight)
        main_layout.addWidget(self._shape_combo_box, 2, 2)
        main_layout.addWidget(pen_width_label, 3, 1, Qt.AlignRight)
        main_layout.addWidget(self._pen_width_spin_box, 3, 2)
        main_layout.addWidget(pen_style_label, 4, 1, Qt.AlignRight)
        main_layout.addWidget(self._pen_style_combo_box, 4, 2)
        main_layout.addWidget(pen_cap_label, 5, 1, Qt.AlignRight)
        main_layout.addWidget(self._pen_cap_combo_box, 5, 2)
        main_layout.addWidget(pen_join_label, 6, 1, Qt.AlignRight)
        main_layout.addWidget(self._pen_join_combo_box, 6, 2)
        main_layout.addWidget(brush_style_label, 7, 1, Qt.AlignRight)
        main_layout.addWidget(self._brush_style_combo_box, 7, 2)
        main_layout.setRowMinimumHeight(8, 6)
        main_layout.addWidget(other_options_label, 9, 1, Qt.AlignRight)
        main_layout.addWidget(self._antialiasing_check_box, 9, 2)
        main_layout.addWidget(self._transformations_check_box, 10, 2)
        self.setLayout(main_layout)

        self.shape_changed()
        self.pen_changed()
        self.brush_changed()
        self._antialiasing_check_box.setChecked(True)

        self.setWindowTitle("Basic Drawing")

    def shape_changed(self):
        shape = self._shape_combo_box.itemData(self._shape_combo_box.currentIndex(), id_role)
        self._render_area.set_shape(shape)

    def pen_changed(self):
        width = self._pen_width_spin_box.value()
        style = Qt.PenStyle(self._pen_style_combo_box.itemData(
            self._pen_style_combo_box.currentIndex(), id_role))
        cap = Qt.PenCapStyle(self._pen_cap_combo_box.itemData(
            self._pen_cap_combo_box.currentIndex(), id_role))
        join = Qt.PenJoinStyle(self._pen_join_combo_box.itemData(
            self._pen_join_combo_box.currentIndex(), id_role))

        self._render_area.set_pen(QPen(Qt.blue, width, style, cap, join))

    def brush_changed(self):
        style = Qt.BrushStyle(self._brush_style_combo_box.itemData(
            self._brush_style_combo_box.currentIndex(), id_role))

        if style == Qt.LinearGradientPattern:
            linear_gradient = QLinearGradient(0, 0, 100, 100)
            linear_gradient.setColorAt(0.0, Qt.white)
            linear_gradient.setColorAt(0.2, Qt.green)
            linear_gradient.setColorAt(1.0, Qt.black)
            self._render_area.set_brush(QBrush(linear_gradient))
        elif style == Qt.RadialGradientPattern:
            radial_gradient = QRadialGradient(50, 50, 50, 70, 70)
            radial_gradient.setColorAt(0.0, Qt.white)
            radial_gradient.setColorAt(0.2, Qt.green)
            radial_gradient.setColorAt(1.0, Qt.black)
            self._render_area.set_brush(QBrush(radial_gradient))
        elif style == Qt.ConicalGradientPattern:
            conical_gradient = QConicalGradient(50, 50, 150)
            conical_gradient.setColorAt(0.0, Qt.white)
            conical_gradient.setColorAt(0.2, Qt.green)
            conical_gradient.setColorAt(1.0, Qt.black)
            self._render_area.set_brush(QBrush(conical_gradient))
        elif style == Qt.TexturePattern:
            self._render_area.set_brush(QBrush(QPixmap(':/images/brick.png')))
        else:
            self._render_area.set_brush(QBrush(Qt.green, style))


if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec())