aboutsummaryrefslogtreecommitdiffstats
path: root/examples/widgets/painting
diff options
context:
space:
mode:
Diffstat (limited to 'examples/widgets/painting')
-rw-r--r--examples/widgets/painting/basicdrawing/basicdrawing.py501
-rw-r--r--examples/widgets/painting/basicdrawing/basicdrawing.pyproject3
-rw-r--r--examples/widgets/painting/basicdrawing/basicdrawing_rc.py90
-rw-r--r--examples/widgets/painting/basicdrawing/doc/basicdrawing.pngbin0 -> 18655 bytes
-rw-r--r--examples/widgets/painting/basicdrawing/doc/basicdrawing.rst15
-rw-r--r--examples/widgets/painting/concentriccircles.py146
-rw-r--r--examples/widgets/painting/concentriccircles/concentriccircles.py109
-rw-r--r--examples/widgets/painting/concentriccircles/concentriccircles.pyproject3
-rw-r--r--examples/widgets/painting/concentriccircles/doc/concentriccircles.pngbin0 -> 51606 bytes
-rw-r--r--examples/widgets/painting/concentriccircles/doc/concentriccircles.rst12
-rw-r--r--examples/widgets/painting/painter/doc/painter.pngbin0 -> 11442 bytes
-rw-r--r--examples/widgets/painting/painter/doc/painter.rst8
-rw-r--r--examples/widgets/painting/painter/painter.py204
-rw-r--r--examples/widgets/painting/painter/painter.pyproject3
-rw-r--r--examples/widgets/painting/plot/doc/plot.pngbin0 -> 13030 bytes
-rw-r--r--examples/widgets/painting/plot/doc/plot.rst36
-rw-r--r--examples/widgets/painting/plot/plot.py66
-rw-r--r--examples/widgets/painting/plot/plot.pyproject3
18 files changed, 738 insertions, 461 deletions
diff --git a/examples/widgets/painting/basicdrawing/basicdrawing.py b/examples/widgets/painting/basicdrawing/basicdrawing.py
index f92da1bd7..858a8cd9f 100644
--- a/examples/widgets/painting/basicdrawing/basicdrawing.py
+++ b/examples/widgets/painting/basicdrawing/basicdrawing.py
@@ -1,54 +1,17 @@
+# Copyright (C) 2013 Riverbank Computing Limited.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#############################################################################
-##
-## Copyright (C) 2013 Riverbank Computing Limited.
-## Copyright (C) 2016 The Qt Company Ltd.
-## Contact: http://www.qt.io/licensing/
-##
-## This file is part of the Qt for Python examples of the Qt Toolkit.
-##
-## $QT_BEGIN_LICENSE:BSD$
-## You may use this file under the terms of the BSD license as follows:
-##
-## "Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions are
-## met:
-## * Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-## * Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in
-## the documentation and/or other materials provided with the
-## distribution.
-## * Neither the name of The Qt Company Ltd nor the names of its
-## contributors may be used to endorse or promote products derived
-## from this software without specific prior written permission.
-##
-##
-## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-"""PySide2 port of the widgets/painting/basicdrawing example from Qt v5.x, originating from PyQt"""
-
-from PySide2.QtCore import QPoint, QRect, QSize, Qt, qVersion
-from PySide2.QtGui import (QBrush, QConicalGradient, QLinearGradient, QPainter,
- QPainterPath, QPalette, QPen, QPixmap, QPolygon, QRadialGradient)
-from PySide2.QtWidgets import (QApplication, QCheckBox, QComboBox, QGridLayout,
- QLabel, QSpinBox, QWidget)
-
-import basicdrawing_rc
+"""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):
@@ -59,11 +22,11 @@ class RenderArea(QWidget):
QPoint(90, 70)
])
- Line, Points, Polyline, Polygon, Rect, RoundedRect, Ellipse, Arc, Chord, \
- Pie, Path, Text, Pixmap = range(13)
+ (Line, Points, Polyline, Polygon, Rect, RoundedRect, Ellipse,
+ Arc, Chord, Pie, Path, Text, Pixmap) = range(13)
def __init__(self, parent=None):
- super(RenderArea, self).__init__(parent)
+ super().__init__(parent)
self.pen = QPen()
self.brush = QBrush()
@@ -83,23 +46,23 @@ class RenderArea(QWidget):
def sizeHint(self):
return QSize(400, 200)
- def setShape(self, shape):
+ def set_shape(self, shape):
self.shape = shape
self.update()
- def setPen(self, pen):
+ def set_pen(self, pen):
self.pen = pen
self.update()
- def setBrush(self, brush):
+ def set_brush(self, brush):
self.brush = brush
self.update()
- def setAntialiased(self, antialiased):
+ def set_antialiased(self, antialiased):
self.antialiased = antialiased
self.update()
- def setTransformed(self, transformed):
+ def set_transformed(self, transformed):
self.transformed = transformed
self.update()
@@ -111,232 +74,230 @@ class RenderArea(QWidget):
path.lineTo(20, 30)
path.cubicTo(80, 0, 50, 50, 80, 80)
- startAngle = 30 * 16
- arcLength = 120 * 16
-
- painter = QPainter(self)
- painter.setPen(self.pen)
- painter.setBrush(self.brush)
- if self.antialiased:
- painter.setRenderHint(QPainter.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, startAngle, arcLength)
- elif self.shape == RenderArea.Chord:
- painter.drawChord(rect, startAngle, arcLength)
- elif self.shape == RenderArea.Pie:
- painter.drawPie(rect, startAngle, arcLength)
- elif self.shape == RenderArea.Path:
- painter.drawPath(path)
- elif self.shape == RenderArea.Text:
- painter.drawText(rect, Qt.AlignCenter,
- "PySide 2\nQt %s" % qVersion())
- 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))
-
-
-IdRole = Qt.UserRole
+ 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.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.UserRole
+
class Window(QWidget):
def __init__(self):
- super(Window, self).__init__()
-
- self.renderArea = RenderArea()
-
- self.shapeComboBox = QComboBox()
- self.shapeComboBox.addItem("Polygon", RenderArea.Polygon)
- self.shapeComboBox.addItem("Rectangle", RenderArea.Rect)
- self.shapeComboBox.addItem("Rounded Rectangle", RenderArea.RoundedRect)
- self.shapeComboBox.addItem("Ellipse", RenderArea.Ellipse)
- self.shapeComboBox.addItem("Pie", RenderArea.Pie)
- self.shapeComboBox.addItem("Chord", RenderArea.Chord)
- self.shapeComboBox.addItem("Path", RenderArea.Path)
- self.shapeComboBox.addItem("Line", RenderArea.Line)
- self.shapeComboBox.addItem("Polyline", RenderArea.Polyline)
- self.shapeComboBox.addItem("Arc", RenderArea.Arc)
- self.shapeComboBox.addItem("Points", RenderArea.Points)
- self.shapeComboBox.addItem("Text", RenderArea.Text)
- self.shapeComboBox.addItem("Pixmap", RenderArea.Pixmap)
-
- shapeLabel = QLabel("&Shape:")
- shapeLabel.setBuddy(self.shapeComboBox)
-
- self.penWidthSpinBox = QSpinBox()
- self.penWidthSpinBox.setRange(0, 20)
- self.penWidthSpinBox.setSpecialValueText("0 (cosmetic pen)")
-
- penWidthLabel = QLabel("Pen &Width:")
- penWidthLabel.setBuddy(self.penWidthSpinBox)
-
- self.penStyleComboBox = QComboBox()
- self.penStyleComboBox.addItem("Solid", Qt.SolidLine)
- self.penStyleComboBox.addItem("Dash", Qt.DashLine)
- self.penStyleComboBox.addItem("Dot", Qt.DotLine)
- self.penStyleComboBox.addItem("Dash Dot", Qt.DashDotLine)
- self.penStyleComboBox.addItem("Dash Dot Dot", Qt.DashDotDotLine)
- self.penStyleComboBox.addItem("None", Qt.NoPen)
-
- penStyleLabel = QLabel("&Pen Style:")
- penStyleLabel.setBuddy(self.penStyleComboBox)
-
- self.penCapComboBox = QComboBox()
- self.penCapComboBox.addItem("Flat", Qt.FlatCap)
- self.penCapComboBox.addItem("Square", Qt.SquareCap)
- self.penCapComboBox.addItem("Round", Qt.RoundCap)
-
- penCapLabel = QLabel("Pen &Cap:")
- penCapLabel.setBuddy(self.penCapComboBox)
-
- self.penJoinComboBox = QComboBox()
- self.penJoinComboBox.addItem("Miter", Qt.MiterJoin)
- self.penJoinComboBox.addItem("Bevel", Qt.BevelJoin)
- self.penJoinComboBox.addItem("Round", Qt.RoundJoin)
-
- penJoinLabel = QLabel("Pen &Join:")
- penJoinLabel.setBuddy(self.penJoinComboBox)
-
- self.brushStyleComboBox = QComboBox()
- self.brushStyleComboBox.addItem("Linear Gradient",
- Qt.LinearGradientPattern)
- self.brushStyleComboBox.addItem("Radial Gradient",
- Qt.RadialGradientPattern)
- self.brushStyleComboBox.addItem("Conical Gradient",
- Qt.ConicalGradientPattern)
- self.brushStyleComboBox.addItem("Texture", Qt.TexturePattern)
- self.brushStyleComboBox.addItem("Solid", Qt.SolidPattern)
- self.brushStyleComboBox.addItem("Horizontal", Qt.HorPattern)
- self.brushStyleComboBox.addItem("Vertical", Qt.VerPattern)
- self.brushStyleComboBox.addItem("Cross", Qt.CrossPattern)
- self.brushStyleComboBox.addItem("Backward Diagonal", Qt.BDiagPattern)
- self.brushStyleComboBox.addItem("Forward Diagonal", Qt.FDiagPattern)
- self.brushStyleComboBox.addItem("Diagonal Cross", Qt.DiagCrossPattern)
- self.brushStyleComboBox.addItem("Dense 1", Qt.Dense1Pattern)
- self.brushStyleComboBox.addItem("Dense 2", Qt.Dense2Pattern)
- self.brushStyleComboBox.addItem("Dense 3", Qt.Dense3Pattern)
- self.brushStyleComboBox.addItem("Dense 4", Qt.Dense4Pattern)
- self.brushStyleComboBox.addItem("Dense 5", Qt.Dense5Pattern)
- self.brushStyleComboBox.addItem("Dense 6", Qt.Dense6Pattern)
- self.brushStyleComboBox.addItem("Dense 7", Qt.Dense7Pattern)
- self.brushStyleComboBox.addItem("None", Qt.NoBrush)
-
- brushStyleLabel = QLabel("&Brush Style:")
- brushStyleLabel.setBuddy(self.brushStyleComboBox)
-
- otherOptionsLabel = QLabel("Other Options:")
- self.antialiasingCheckBox = QCheckBox("&Antialiasing")
- self.transformationsCheckBox = QCheckBox("&Transformations")
-
- self.shapeComboBox.activated.connect(self.shapeChanged)
- self.penWidthSpinBox.valueChanged.connect(self.penChanged)
- self.penStyleComboBox.activated.connect(self.penChanged)
- self.penCapComboBox.activated.connect(self.penChanged)
- self.penJoinComboBox.activated.connect(self.penChanged)
- self.brushStyleComboBox.activated.connect(self.brushChanged)
- self.antialiasingCheckBox.toggled.connect(self.renderArea.setAntialiased)
- self.transformationsCheckBox.toggled.connect(self.renderArea.setTransformed)
-
- mainLayout = QGridLayout()
- mainLayout.setColumnStretch(0, 1)
- mainLayout.setColumnStretch(3, 1)
- mainLayout.addWidget(self.renderArea, 0, 0, 1, 4)
- mainLayout.setRowMinimumHeight(1, 6)
- mainLayout.addWidget(shapeLabel, 2, 1, Qt.AlignRight)
- mainLayout.addWidget(self.shapeComboBox, 2, 2)
- mainLayout.addWidget(penWidthLabel, 3, 1, Qt.AlignRight)
- mainLayout.addWidget(self.penWidthSpinBox, 3, 2)
- mainLayout.addWidget(penStyleLabel, 4, 1, Qt.AlignRight)
- mainLayout.addWidget(self.penStyleComboBox, 4, 2)
- mainLayout.addWidget(penCapLabel, 5, 1, Qt.AlignRight)
- mainLayout.addWidget(self.penCapComboBox, 5, 2)
- mainLayout.addWidget(penJoinLabel, 6, 1, Qt.AlignRight)
- mainLayout.addWidget(self.penJoinComboBox, 6, 2)
- mainLayout.addWidget(brushStyleLabel, 7, 1, Qt.AlignRight)
- mainLayout.addWidget(self.brushStyleComboBox, 7, 2)
- mainLayout.setRowMinimumHeight(8, 6)
- mainLayout.addWidget(otherOptionsLabel, 9, 1, Qt.AlignRight)
- mainLayout.addWidget(self.antialiasingCheckBox, 9, 2)
- mainLayout.addWidget(self.transformationsCheckBox, 10, 2)
- self.setLayout(mainLayout)
-
- self.shapeChanged()
- self.penChanged()
- self.brushChanged()
- self.antialiasingCheckBox.setChecked(True)
+ 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 shapeChanged(self):
- shape = self.shapeComboBox.itemData(self.shapeComboBox.currentIndex(),
- IdRole)
- self.renderArea.setShape(shape)
+ def shape_changed(self):
+ shape = self._shape_combo_box.itemData(self._shape_combo_box.currentIndex(), id_role)
+ self._render_area.set_shape(shape)
- def penChanged(self):
- width = self.penWidthSpinBox.value()
- style = Qt.PenStyle(self.penStyleComboBox.itemData(
- self.penStyleComboBox.currentIndex(), IdRole))
- cap = Qt.PenCapStyle(self.penCapComboBox.itemData(
- self.penCapComboBox.currentIndex(), IdRole))
- join = Qt.PenJoinStyle(self.penJoinComboBox.itemData(
- self.penJoinComboBox.currentIndex(), IdRole))
+ 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.renderArea.setPen(QPen(Qt.blue, width, style, cap, join))
+ self._render_area.set_pen(QPen(Qt.blue, width, style, cap, join))
- def brushChanged(self):
- style = Qt.BrushStyle(self.brushStyleComboBox.itemData(
- self.brushStyleComboBox.currentIndex(), IdRole))
+ 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:
- linearGradient = QLinearGradient(0, 0, 100, 100)
- linearGradient.setColorAt(0.0, Qt.white)
- linearGradient.setColorAt(0.2, Qt.green)
- linearGradient.setColorAt(1.0, Qt.black)
- self.renderArea.setBrush(QBrush(linearGradient))
+ 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:
- radialGradient = QRadialGradient(50, 50, 50, 70, 70)
- radialGradient.setColorAt(0.0, Qt.white)
- radialGradient.setColorAt(0.2, Qt.green)
- radialGradient.setColorAt(1.0, Qt.black)
- self.renderArea.setBrush(QBrush(radialGradient))
+ 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:
- conicalGradient = QConicalGradient(50, 50, 150)
- conicalGradient.setColorAt(0.0, Qt.white)
- conicalGradient.setColorAt(0.2, Qt.green)
- conicalGradient.setColorAt(1.0, Qt.black)
- self.renderArea.setBrush(QBrush(conicalGradient))
+ 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.renderArea.setBrush(QBrush(QPixmap(':/images/brick.png')))
+ self._render_area.set_brush(QBrush(QPixmap(':/images/brick.png')))
else:
- self.renderArea.setBrush(QBrush(Qt.green, style))
+ self._render_area.set_brush(QBrush(Qt.green, style))
if __name__ == '__main__':
@@ -346,4 +307,4 @@ if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
- sys.exit(app.exec_())
+ sys.exit(app.exec())
diff --git a/examples/widgets/painting/basicdrawing/basicdrawing.pyproject b/examples/widgets/painting/basicdrawing/basicdrawing.pyproject
new file mode 100644
index 000000000..976bb9e35
--- /dev/null
+++ b/examples/widgets/painting/basicdrawing/basicdrawing.pyproject
@@ -0,0 +1,3 @@
+{
+ "files": ["basicdrawing.qrc", "basicdrawing.py"]
+}
diff --git a/examples/widgets/painting/basicdrawing/basicdrawing_rc.py b/examples/widgets/painting/basicdrawing/basicdrawing_rc.py
index 3a5480568..701f1610b 100644
--- a/examples/widgets/painting/basicdrawing/basicdrawing_rc.py
+++ b/examples/widgets/painting/basicdrawing/basicdrawing_rc.py
@@ -1,11 +1,47 @@
# Resource object code (Python 3)
# Created by: object code
-# Created by: The Resource Compiler for Qt version 5.14.0
+# Created by: The Resource Compiler for Qt version 6.2.2
# WARNING! All changes made in this file will be lost!
-from PySide2 import QtCore
+from PySide6 import QtCore
qt_resource_data = b"\
+\x00\x00\x02\x15\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00P\x00\x00\x00P\x04\x03\x00\x00\x00|?\xef\x9e\
+\x00\x00\x00\x15PLTE\xa3\xc2\x00\xf4\xf8\xe1\x8a\xa1\
+\x09\x14\x14\x18?G\x16\xd3\xe2\x86p\x82\x0e\xfd\x17\x22\
+9\x00\x00\x00\x09pHYs\x00\x00\x00H\x00\x00\x00\
+H\x00F\xc9k>\x00\x00\x01\xa6IDATH\xc7\
+\xedVKn\x840\x0cEf\xc49\xa2I\xd55\x22\
+\x11k\xd4Hs\x0eT\x10\xf7?B\x0b\xc4L\xfc\x83\
+\xd9u\xd1\xf1\x0a\xa2\x97\x17\xdb\xb1\x9fSUo\xfbk\
+\xbb/\xcb\xfd\x1a\x05s\x0a\xbf\x16\x1f\xee\x1c\xd7l\xb0\
+\x0d:\x9e\xe2Ba\xe3\x8b\xb8\x13$$\x0a\x8c\x96\x9f\
+S`\xd6\xeb\xb8[\x106\xa8\xc0$\x81\xf1EB\x9d\
+\x12\x09\xe3cY\xe6dSbj\xf6+\x81\xd9\xa4\xf4\
+\x19\x87\xff\x1fV\xe0\x89\xaf\xe7d9=\x14'\xd2?\
+\xa8'\x7f\xc9\xbd\x9dz\xf2\x93n\xc45\x167\xb0\xdd\
+~u\xb6VJ\xe3F\xd7`\xfb\x06\xc5\xc9\x9a\x9e\xe2\
+\xf7\xf8\x93tr\x22K\x90\xe9k\x99\xc9D\x0e\xf1\x19\
+\xd0\xc8hR\x99D\xc0\x02\x07\x91r [\xf3m\xb6\
+l\xffQ\x11=%\x5c\x9d\x9cx~\x080\x13v\xf8\
+9\xf04v\x94\xd0a\xd6\x04\xb0\x15\x84\xfb\xba\x01\x84\
+\xb2\xa9u\xe0P\x12\xf6\xd5\x05#\x84k\xc6\xb6 \xcc\
+\x9473j\xa0\xca#\xa2>\xf2\xe8\xa9\x9ex\x15\x18\
+\x09\xa1~3x\xd75\x93(q\xd7\xb8\x02T\x1f\x81\
+6RY\x8f\x9bS\x1d\xe6R\xa9G\xacp(\x98B\
+\x98d\x85\x1f=\xb3wK\x11<\xeb\x99\xa3\x0bas\
+\x1eL\xe5{\xf6\xb5\xef*\x9aO\xa7)\x85\xcb\x1aQ\
+PFU{:\xae\x82R{\x1av\x0e\x98\xe2\xcc\xf5\
+\x11)-\xc5=\x90\xb35\xbeP\xc3{\xaa\xe1\xa66\
+\xb3\xa9\xa0Q\xaas\xe6\x94\x92\xdbx1\x84O\xa6\xd7\
+\xa4\xe2\xe2\x0b\xf3z\xb2\xc6a\x93d\x85\xc7\x8b\xb7\xc7\
+\x1e\x84\xb7F6\x7f\xa5\x80A\xb8\xda\x92\xdf=\xf9b\
+\x87\xb3\x97\xd4\xe7\xf7\xf1\x92\x02\xf7~Y\xfe?\xfb\x01\
+\xbd\xf6\xdd\x91\xa2\xf3\xda\xd4\x00\x00\x00\x00IEND\
+\xaeB`\x82\
\x00\x00\x03X\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@@ -62,42 +98,6 @@ m\x84\xd3O\x00\xdb\xe6\xee\xebD+\x94p|\xf0\xc7\
W]\x06\xe4\xfcAY\xbf\xb5\x08Wn\x8a\xce9\x97\
\xe4\xfe\x07\xb6\x84\x15$\x5c\xbcO\xce\x00\x00\x00\x00I\
END\xaeB`\x82\
-\x00\x00\x02\x15\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00P\x00\x00\x00P\x04\x03\x00\x00\x00|?\xef\x9e\
-\x00\x00\x00\x15PLTE\xa3\xc2\x00\xf4\xf8\xe1\x8a\xa1\
-\x09\x14\x14\x18?G\x16\xd3\xe2\x86p\x82\x0e\xfd\x17\x22\
-9\x00\x00\x00\x09pHYs\x00\x00\x00H\x00\x00\x00\
-H\x00F\xc9k>\x00\x00\x01\xa6IDATH\xc7\
-\xedVKn\x840\x0cEf\xc49\xa2I\xd55\x22\
-\x11k\xd4Hs\x0eT\x10\xf7?B\x0b\xc4L\xfc\x83\
-\xd9u\xd1\xf1\x0a\xa2\x97\x17\xdb\xb1\x9fSUo\xfbk\
-\xbb/\xcb\xfd\x1a\x05s\x0a\xbf\x16\x1f\xee\x1c\xd7l\xb0\
-\x0d:\x9e\xe2Ba\xe3\x8b\xb8\x13$$\x0a\x8c\x96\x9f\
-S`\xd6\xeb\xb8[\x106\xa8\xc0$\x81\xf1EB\x9d\
-\x12\x09\xe3cY\xe6dSbj\xf6+\x81\xd9\xa4\xf4\
-\x19\x87\xff\x1fV\xe0\x89\xaf\xe7d9=\x14'\xd2?\
-\xa8'\x7f\xc9\xbd\x9dz\xf2\x93n\xc45\x167\xb0\xdd\
-~u\xb6VJ\xe3F\xd7`\xfb\x06\xc5\xc9\x9a\x9e\xe2\
-\xf7\xf8\x93tr\x22K\x90\xe9k\x99\xc9D\x0e\xf1\x19\
-\xd0\xc8hR\x99D\xc0\x02\x07\x91r [\xf3m\xb6\
-l\xffQ\x11=%\x5c\x9d\x9cx~\x080\x13v\xf8\
-9\xf04v\x94\xd0a\xd6\x04\xb0\x15\x84\xfb\xba\x01\x84\
-\xb2\xa9u\xe0P\x12\xf6\xd5\x05#\x84k\xc6\xb6 \xcc\
-\x9473j\xa0\xca#\xa2>\xf2\xe8\xa9\x9ex\x15\x18\
-\x09\xa1~3x\xd75\x93(q\xd7\xb8\x02T\x1f\x81\
-6RY\x8f\x9bS\x1d\xe6R\xa9G\xacp(\x98B\
-\x98d\x85\x1f=\xb3wK\x11<\xeb\x99\xa3\x0bas\
-\x1eL\xe5{\xf6\xb5\xef*\x9aO\xa7)\x85\xcb\x1aQ\
-PFU{:\xae\x82R{\x1av\x0e\x98\xe2\xcc\xf5\
-\x11)-\xc5=\x90\xb35\xbeP\xc3{\xaa\xe1\xa66\
-\xb3\xa9\xa0Q\xaas\xe6\x94\x92\xdbx1\x84O\xa6\xd7\
-\xa4\xe2\xe2\x0b\xf3z\xb2\xc6a\x93d\x85\xc7\x8b\xb7\xc7\
-\x1e\x84\xb7F6\x7f\xa5\x80A\xb8\xda\x92\xdf=\xf9b\
-\x87\xb3\x97\xd4\xe7\xf7\xf1\x92\x02\xf7~Y\xfe?\xfb\x01\
-\xbd\xf6\xdd\x91\xa2\xf3\xda\xd4\x00\x00\x00\x00IEND\
-\xaeB`\x82\
"
qt_resource_name = b"\
@@ -105,14 +105,14 @@ qt_resource_name = b"\
\x07\x03}\xc3\
\x00i\
\x00m\x00a\x00g\x00e\x00s\
-\x00\x09\
-\x0f\x9e\x84G\
-\x00b\
-\x00r\x00i\x00c\x00k\x00.\x00p\x00n\x00g\
\x00\x0b\
\x05R\xbf'\
\x00q\
\x00t\x00-\x00l\x00o\x00g\x00o\x00.\x00p\x00n\x00g\
+\x00\x09\
+\x0f\x9e\x84G\
+\x00b\
+\x00r\x00i\x00c\x00k\x00.\x00p\x00n\x00g\
"
qt_resource_struct = b"\
@@ -120,10 +120,10 @@ qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00*\x00\x00\x00\x00\x00\x01\x00\x00\x03\x5c\
-\x00\x00\x01e\xaf\x16\xd2\xa1\
\x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01e\xaf\x16\xd2\xa1\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x00.\x00\x00\x00\x00\x00\x01\x00\x00\x02\x19\
+\x00\x00\x01z\xe7\xee'\x09\
"
def qInitResources():
diff --git a/examples/widgets/painting/basicdrawing/doc/basicdrawing.png b/examples/widgets/painting/basicdrawing/doc/basicdrawing.png
new file mode 100644
index 000000000..30be31724
--- /dev/null
+++ b/examples/widgets/painting/basicdrawing/doc/basicdrawing.png
Binary files differ
diff --git a/examples/widgets/painting/basicdrawing/doc/basicdrawing.rst b/examples/widgets/painting/basicdrawing/doc/basicdrawing.rst
new file mode 100644
index 000000000..26aa8c997
--- /dev/null
+++ b/examples/widgets/painting/basicdrawing/doc/basicdrawing.rst
@@ -0,0 +1,15 @@
+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.
+
+.. image:: stardelegate.png
+ :width: 400
+ :alt: Basic Drawing Screenshot
diff --git a/examples/widgets/painting/concentriccircles.py b/examples/widgets/painting/concentriccircles.py
deleted file mode 100644
index ff13292d2..000000000
--- a/examples/widgets/painting/concentriccircles.py
+++ /dev/null
@@ -1,146 +0,0 @@
-
-#############################################################################
-##
-## Copyright (C) 2013 Riverbank Computing Limited.
-## Copyright (C) 2016 The Qt Company Ltd.
-## Contact: http://www.qt.io/licensing/
-##
-## This file is part of the Qt for Python examples of the Qt Toolkit.
-##
-## $QT_BEGIN_LICENSE:BSD$
-## You may use this file under the terms of the BSD license as follows:
-##
-## "Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions are
-## met:
-## * Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-## * Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in
-## the documentation and/or other materials provided with the
-## distribution.
-## * Neither the name of The Qt Company Ltd nor the names of its
-## contributors may be used to endorse or promote products derived
-## from this software without specific prior written permission.
-##
-##
-## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-"""PySide2 port of the widgets/painting/concentriccircles example from Qt v5.x, originating from PyQt"""
-
-from PySide2.QtCore import QRect, QRectF, QSize, Qt, QTimer
-from PySide2.QtGui import QColor, QPainter, QPalette, QPen
-from PySide2.QtWidgets import (QApplication, QFrame, QGridLayout, QLabel,
- QSizePolicy, QWidget)
-
-
-class CircleWidget(QWidget):
- def __init__(self, parent=None):
- super(CircleWidget, self).__init__(parent)
-
- self.floatBased = False
- self.antialiased = False
- self.frameNo = 0
-
- self.setBackgroundRole(QPalette.Base)
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
-
- def setFloatBased(self, floatBased):
- self.floatBased = floatBased
- self.update()
-
- def setAntialiased(self, antialiased):
- self.antialiased = antialiased
- self.update()
-
- def minimumSizeHint(self):
- return QSize(50, 50)
-
- def sizeHint(self):
- return QSize(180, 180)
-
- def nextAnimationFrame(self):
- self.frameNo += 1
- self.update()
-
- def paintEvent(self, event):
- painter = QPainter(self)
- painter.setRenderHint(QPainter.Antialiasing, self.antialiased)
- painter.translate(self.width() / 2, self.height() / 2)
-
- for diameter in range(0, 256, 9):
- delta = abs((self.frameNo % 128) - diameter / 2)
- alpha = 255 - (delta * delta) / 4 - diameter
- if alpha > 0:
- painter.setPen(QPen(QColor(0, diameter / 2, 127, alpha), 3))
-
- if self.floatBased:
- painter.drawEllipse(QRectF(-diameter / 2.0,
- -diameter / 2.0, diameter, diameter))
- else:
- painter.drawEllipse(QRect(-diameter / 2,
- -diameter / 2, diameter, diameter))
-
-
-class Window(QWidget):
- def __init__(self):
- super(Window, self).__init__()
-
- aliasedLabel = self.createLabel("Aliased")
- antialiasedLabel = self.createLabel("Antialiased")
- intLabel = self.createLabel("Int")
- floatLabel = self.createLabel("Float")
-
- layout = QGridLayout()
- layout.addWidget(aliasedLabel, 0, 1)
- layout.addWidget(antialiasedLabel, 0, 2)
- layout.addWidget(intLabel, 1, 0)
- layout.addWidget(floatLabel, 2, 0)
-
- timer = QTimer(self)
-
- for i in range(2):
- for j in range(2):
- w = CircleWidget()
- w.setAntialiased(j != 0)
- w.setFloatBased(i != 0)
-
- timer.timeout.connect(w.nextAnimationFrame)
-
- layout.addWidget(w, i + 1, j + 1)
-
- timer.start(100)
- self.setLayout(layout)
-
- self.setWindowTitle("Concentric Circles")
-
- def createLabel(self, text):
- label = QLabel(text)
- label.setAlignment(Qt.AlignCenter)
- label.setMargin(2)
- label.setFrameStyle(QFrame.Box | QFrame.Sunken)
- return label
-
-
-if __name__ == '__main__':
-
- import sys
-
- app = QApplication(sys.argv)
- window = Window()
- window.show()
- sys.exit(app.exec_())
diff --git a/examples/widgets/painting/concentriccircles/concentriccircles.py b/examples/widgets/painting/concentriccircles/concentriccircles.py
new file mode 100644
index 000000000..d2c60178f
--- /dev/null
+++ b/examples/widgets/painting/concentriccircles/concentriccircles.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2013 Riverbank Computing Limited.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""PySide6 port of the widgets/painting/concentriccircles example from Qt v5.x, originating
+ from PyQt"""
+
+from PySide6.QtCore import QRect, QRectF, QSize, Qt, QTimer
+from PySide6.QtGui import QColor, QPainter, QPalette, QPen
+from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QLabel,
+ QSizePolicy, QWidget)
+
+
+class CircleWidget(QWidget):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self._float_based = False
+ self.antialiased = False
+ self._frame_no = 0
+
+ self.setBackgroundRole(QPalette.Base)
+ self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+
+ def set_float_based(self, floatBased):
+ self._float_based = floatBased
+ self.update()
+
+ def set_antialiased(self, antialiased):
+ self.antialiased = antialiased
+ self.update()
+
+ def minimumSizeHint(self):
+ return QSize(50, 50)
+
+ def sizeHint(self):
+ return QSize(180, 180)
+
+ def next_animation_frame(self):
+ self._frame_no += 1
+ self.update()
+
+ def paintEvent(self, event):
+ with QPainter(self) as painter:
+ painter.setRenderHint(QPainter.Antialiasing, self.antialiased)
+ painter.translate(self.width() / 2, self.height() / 2)
+
+ for diameter in range(0, 256, 9):
+ delta = abs((self._frame_no % 128) - diameter / 2)
+ alpha = 255 - (delta * delta) / 4 - diameter
+ if alpha > 0:
+ painter.setPen(QPen(QColor(0, diameter / 2, 127, alpha), 3))
+
+ if self._float_based:
+ painter.drawEllipse(QRectF(-diameter / 2.0,
+ -diameter / 2.0, diameter, diameter))
+ else:
+ painter.drawEllipse(QRect(-diameter / 2,
+ -diameter / 2, diameter, diameter))
+
+
+class Window(QWidget):
+ def __init__(self):
+ super().__init__()
+
+ aliased_label = self.create_label("Aliased")
+ antialiased_label = self.create_label("Antialiased")
+ int_label = self.create_label("Int")
+ float_label = self.create_label("Float")
+
+ layout = QGridLayout()
+ layout.addWidget(aliased_label, 0, 1)
+ layout.addWidget(antialiased_label, 0, 2)
+ layout.addWidget(int_label, 1, 0)
+ layout.addWidget(float_label, 2, 0)
+
+ timer = QTimer(self)
+
+ for i in range(2):
+ for j in range(2):
+ w = CircleWidget()
+ w.set_antialiased(j != 0)
+ w.set_float_based(i != 0)
+
+ timer.timeout.connect(w.next_animation_frame)
+
+ layout.addWidget(w, i + 1, j + 1)
+
+ timer.start(100)
+ self.setLayout(layout)
+
+ self.setWindowTitle("Concentric Circles")
+
+ def create_label(self, text):
+ label = QLabel(text)
+ label.setAlignment(Qt.AlignCenter)
+ label.setMargin(2)
+ label.setFrameStyle(QFrame.Box | QFrame.Sunken)
+ return label
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QApplication(sys.argv)
+ window = Window()
+ window.show()
+ sys.exit(app.exec())
diff --git a/examples/widgets/painting/concentriccircles/concentriccircles.pyproject b/examples/widgets/painting/concentriccircles/concentriccircles.pyproject
new file mode 100644
index 000000000..ed24e12b0
--- /dev/null
+++ b/examples/widgets/painting/concentriccircles/concentriccircles.pyproject
@@ -0,0 +1,3 @@
+{
+ "files": ["concentriccircles.py"]
+}
diff --git a/examples/widgets/painting/concentriccircles/doc/concentriccircles.png b/examples/widgets/painting/concentriccircles/doc/concentriccircles.png
new file mode 100644
index 000000000..69ea16825
--- /dev/null
+++ b/examples/widgets/painting/concentriccircles/doc/concentriccircles.png
Binary files differ
diff --git a/examples/widgets/painting/concentriccircles/doc/concentriccircles.rst b/examples/widgets/painting/concentriccircles/doc/concentriccircles.rst
new file mode 100644
index 000000000..6c1efe0c5
--- /dev/null
+++ b/examples/widgets/painting/concentriccircles/doc/concentriccircles.rst
@@ -0,0 +1,12 @@
+Concentric Circles Examples
+===========================
+
+Demonstrates the improved quality that antialiasing and floating point
+precision gives.
+
+The application's main window displays several widgets which are drawn using
+the various combinations of precision and anti-aliasing.
+
+.. image:: concentriccircles.png
+ :width: 400
+ :alt: Concentric Circles Screenshot
diff --git a/examples/widgets/painting/painter/doc/painter.png b/examples/widgets/painting/painter/doc/painter.png
new file mode 100644
index 000000000..991d2703d
--- /dev/null
+++ b/examples/widgets/painting/painter/doc/painter.png
Binary files differ
diff --git a/examples/widgets/painting/painter/doc/painter.rst b/examples/widgets/painting/painter/doc/painter.rst
new file mode 100644
index 000000000..69e75a789
--- /dev/null
+++ b/examples/widgets/painting/painter/doc/painter.rst
@@ -0,0 +1,8 @@
+Painter Example
+===============
+
+Simple painter application based on Qt Widgets.
+
+.. image:: painter.png
+ :width: 400
+ :alt: Painter Screenshot
diff --git a/examples/widgets/painting/painter/painter.py b/examples/widgets/painting/painter/painter.py
new file mode 100644
index 000000000..2ca078ad9
--- /dev/null
+++ b/examples/widgets/painting/painter/painter.py
@@ -0,0 +1,204 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtWidgets import (
+ QWidget,
+ QMainWindow,
+ QApplication,
+ QFileDialog,
+ QStyle,
+ QColorDialog,
+)
+from PySide6.QtCore import Qt, Slot, QStandardPaths
+from PySide6.QtGui import (
+ QMouseEvent,
+ QPaintEvent,
+ QPen,
+ QAction,
+ QPainter,
+ QColor,
+ QPixmap,
+ QIcon,
+ QKeySequence,
+)
+import sys
+
+
+class PainterWidget(QWidget):
+ """A widget where user can draw with their mouse
+
+ The user draws on a QPixmap which is itself paint from paintEvent()
+
+ """
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.setFixedSize(680, 480)
+ self.pixmap = QPixmap(self.size())
+ self.pixmap.fill(Qt.white)
+
+ self.previous_pos = None
+ self.painter = QPainter()
+ self.pen = QPen()
+ self.pen.setWidth(10)
+ self.pen.setCapStyle(Qt.RoundCap)
+ self.pen.setJoinStyle(Qt.RoundJoin)
+
+ def paintEvent(self, event: QPaintEvent):
+ """Override method from QWidget
+
+ Paint the Pixmap into the widget
+
+ """
+ with QPainter(self) as painter:
+ painter.drawPixmap(0, 0, self.pixmap)
+
+ def mousePressEvent(self, event: QMouseEvent):
+ """Override from QWidget
+
+ Called when user clicks on the mouse
+
+ """
+ self.previous_pos = event.position().toPoint()
+ QWidget.mousePressEvent(self, event)
+
+ def mouseMoveEvent(self, event: QMouseEvent):
+ """Override method from QWidget
+
+ Called when user moves and clicks on the mouse
+
+ """
+ current_pos = event.position().toPoint()
+ self.painter.begin(self.pixmap)
+ self.painter.setRenderHints(QPainter.Antialiasing, True)
+ self.painter.setPen(self.pen)
+ self.painter.drawLine(self.previous_pos, current_pos)
+ self.painter.end()
+
+ self.previous_pos = current_pos
+ self.update()
+
+ QWidget.mouseMoveEvent(self, event)
+
+ def mouseReleaseEvent(self, event: QMouseEvent):
+ """Override method from QWidget
+
+ Called when user releases the mouse
+
+ """
+ self.previous_pos = None
+ QWidget.mouseReleaseEvent(self, event)
+
+ def save(self, filename: str):
+ """ save pixmap to filename """
+ self.pixmap.save(filename)
+
+ def load(self, filename: str):
+ """ load pixmap from filename """
+ self.pixmap.load(filename)
+ self.pixmap = self.pixmap.scaled(self.size(), Qt.KeepAspectRatio)
+ self.update()
+
+ def clear(self):
+ """ Clear the pixmap """
+ self.pixmap.fill(Qt.white)
+ self.update()
+
+
+class MainWindow(QMainWindow):
+ """An Application example to draw using a pen """
+
+ def __init__(self, parent=None):
+ QMainWindow.__init__(self, parent)
+
+ self.painter_widget = PainterWidget()
+ self.bar = self.addToolBar("Menu")
+ self.bar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
+ self._save_action = self.bar.addAction(
+ qApp.style().standardIcon(QStyle.SP_DialogSaveButton), # noqa: F821
+ "Save", self.on_save
+ )
+ self._save_action.setShortcut(QKeySequence.Save)
+ self._open_action = self.bar.addAction(
+ qApp.style().standardIcon(QStyle.SP_DialogOpenButton), # noqa: F821
+ "Open", self.on_open
+ )
+ self._open_action.setShortcut(QKeySequence.Open)
+ self.bar.addAction(
+ qApp.style().standardIcon(QStyle.SP_DialogResetButton), # noqa: F821
+ "Clear",
+ self.painter_widget.clear,
+ )
+ self.bar.addSeparator()
+
+ self.color_action = QAction(self)
+ self.color_action.triggered.connect(self.on_color_clicked)
+ self.bar.addAction(self.color_action)
+
+ self.setCentralWidget(self.painter_widget)
+
+ self.color = Qt.black
+ self.set_color(self.color)
+
+ self.mime_type_filters = ["image/png", "image/jpeg"]
+
+ @Slot()
+ def on_save(self):
+
+ dialog = QFileDialog(self, "Save File")
+ dialog.setMimeTypeFilters(self.mime_type_filters)
+ dialog.setFileMode(QFileDialog.AnyFile)
+ dialog.setAcceptMode(QFileDialog.AcceptSave)
+ dialog.setDefaultSuffix("png")
+ dialog.setDirectory(
+ QStandardPaths.writableLocation(QStandardPaths.PicturesLocation)
+ )
+
+ if dialog.exec() == QFileDialog.Accepted:
+ if dialog.selectedFiles():
+ self.painter_widget.save(dialog.selectedFiles()[0])
+
+ @Slot()
+ def on_open(self):
+
+ dialog = QFileDialog(self, "Save File")
+ dialog.setMimeTypeFilters(self.mime_type_filters)
+ dialog.setFileMode(QFileDialog.ExistingFile)
+ dialog.setAcceptMode(QFileDialog.AcceptOpen)
+ dialog.setDefaultSuffix("png")
+ dialog.setDirectory(
+ QStandardPaths.writableLocation(QStandardPaths.PicturesLocation)
+ )
+
+ if dialog.exec() == QFileDialog.Accepted:
+ if dialog.selectedFiles():
+ self.painter_widget.load(dialog.selectedFiles()[0])
+
+ @Slot()
+ def on_color_clicked(self):
+
+ color = QColorDialog.getColor(self.color, self)
+
+ if color:
+ self.set_color(color)
+
+ def set_color(self, color: QColor = Qt.black):
+
+ self.color = color
+ # Create color icon
+ pix_icon = QPixmap(32, 32)
+ pix_icon.fill(self.color)
+
+ self.color_action.setIcon(QIcon(pix_icon))
+ self.painter_widget.pen.setColor(self.color)
+ self.color_action.setText(QColor(self.color).name())
+
+
+if __name__ == "__main__":
+
+ app = QApplication(sys.argv)
+
+ w = MainWindow()
+ w.show()
+ sys.exit(app.exec())
diff --git a/examples/widgets/painting/painter/painter.pyproject b/examples/widgets/painting/painter/painter.pyproject
new file mode 100644
index 000000000..f47831696
--- /dev/null
+++ b/examples/widgets/painting/painter/painter.pyproject
@@ -0,0 +1,3 @@
+{
+ "files": ["painter.py"]
+}
diff --git a/examples/widgets/painting/plot/doc/plot.png b/examples/widgets/painting/plot/doc/plot.png
new file mode 100644
index 000000000..e5031e351
--- /dev/null
+++ b/examples/widgets/painting/plot/doc/plot.png
Binary files differ
diff --git a/examples/widgets/painting/plot/doc/plot.rst b/examples/widgets/painting/plot/doc/plot.rst
new file mode 100644
index 000000000..a63eaed87
--- /dev/null
+++ b/examples/widgets/painting/plot/doc/plot.rst
@@ -0,0 +1,36 @@
+Plot Example
+============
+
+The Plot example shows how to display a graph from data using an
+`opaque container <https://doc.qt.io/qtforpython-6/shiboken6/typesystem_containers.html>`_.
+
+It draws an sine graph using ``QPainter.drawPolyline()`` from a list of points.
+The list of points is continuously updated, as is the case for a example for a
+graph of an oscilloscope or medical patient monitor.
+In this case, it makes sense from a performance point of view to avoid the
+conversion of a Python list of data to a C++ list (``QList<QPoint>``)
+for each call to the plot function ``QPainter.drawPolyline()``.
+This is where opaque containers come into play.
+
+Instead of Python list of points, a ``QPointList`` is instantiated to store
+the data. ``QPointList`` is an opaque container wrapping a ``QList<QPoint>``.
+It can be passed to ``QPainter.drawPolyline()`` instead of a Python list of
+points.
+
+The type is declared in the entry for the ``QList`` container type in the
+type system file of the ``QtCore`` library:
+
+.. code-block:: xml
+
+ <container-type name="QList" type="list"
+ opaque-containers="int:QIntList;QPoint:QPointList;QPointF:QPointFList">
+ ...
+ </container-type>
+
+In the ``shift()`` member function, new data are appended to the list while
+old data moving out of the visible window are removed from the front of the
+list.
+
+.. image:: plot.png
+ :width: 400
+ :alt: Plot Screenshot
diff --git a/examples/widgets/painting/plot/plot.py b/examples/widgets/painting/plot/plot.py
new file mode 100644
index 000000000..fd7ff9937
--- /dev/null
+++ b/examples/widgets/painting/plot/plot.py
@@ -0,0 +1,66 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import math
+import sys
+
+from PySide6.QtWidgets import QWidget, QApplication
+from PySide6.QtCore import QPoint, QRect, QTimer, Qt
+from PySide6.QtGui import QPainter, QPointList
+
+
+WIDTH = 680
+HEIGHT = 480
+
+
+class PlotWidget(QWidget):
+ """Illustrates the use of opaque containers. QPointList
+ wraps a C++ QList<QPoint> directly, removing the need to convert
+ a Python list in each call to QPainter.drawPolyline()."""
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._timer = QTimer(self)
+ self._timer.setInterval(20)
+ self._timer.timeout.connect(self.shift)
+
+ self._points = QPointList()
+ self._points.reserve(WIDTH)
+ self._x = 0
+ self._delta_x = 0.05
+ self._half_height = HEIGHT / 2
+ self._factor = 0.8 * self._half_height
+
+ for i in range(WIDTH):
+ self._points.append(QPoint(i, self.next_point()))
+
+ self.setFixedSize(WIDTH, HEIGHT)
+
+ self._timer.start()
+
+ def next_point(self):
+ result = self._half_height - self._factor * math.sin(self._x)
+ self._x += self._delta_x
+ return result
+
+ def shift(self):
+ last_x = self._points[WIDTH - 1].x()
+ self._points.pop_front()
+ self._points.append(QPoint(last_x + 1, self.next_point()))
+ self.update()
+
+ def paintEvent(self, event):
+ with QPainter(self) as painter:
+ rect = QRect(QPoint(0, 0), self.size())
+ painter.fillRect(rect, Qt.white)
+ painter.translate(-self._points[0].x(), 0)
+ painter.drawPolyline(self._points)
+
+
+if __name__ == "__main__":
+
+ app = QApplication(sys.argv)
+
+ w = PlotWidget()
+ w.show()
+ sys.exit(app.exec())
diff --git a/examples/widgets/painting/plot/plot.pyproject b/examples/widgets/painting/plot/plot.pyproject
new file mode 100644
index 000000000..0ac776c83
--- /dev/null
+++ b/examples/widgets/painting/plot/plot.pyproject
@@ -0,0 +1,3 @@
+{
+ "files": ["plot.py"]
+}