aboutsummaryrefslogtreecommitdiffstats
path: root/examples/widgets/graphicsview
diff options
context:
space:
mode:
Diffstat (limited to 'examples/widgets/graphicsview')
-rw-r--r--examples/widgets/graphicsview/anchorlayout.py125
-rw-r--r--examples/widgets/graphicsview/anchorlayout/anchorlayout.py90
-rw-r--r--examples/widgets/graphicsview/anchorlayout/anchorlayout.pyproject3
-rw-r--r--examples/widgets/graphicsview/collidingmice/collidingmice.py212
-rw-r--r--examples/widgets/graphicsview/collidingmice/collidingmice.pyproject2
-rw-r--r--examples/widgets/graphicsview/collidingmice/mice_rc.py47
-rw-r--r--examples/widgets/graphicsview/diagramscene/diagramscene.py1150
-rw-r--r--examples/widgets/graphicsview/diagramscene/diagramscene.pyproject2
-rw-r--r--examples/widgets/graphicsview/diagramscene/diagramscene_rc.py574
-rw-r--r--examples/widgets/graphicsview/dragdroprobot/dragdroprobot.py279
-rw-r--r--examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject2
-rw-r--r--examples/widgets/graphicsview/dragdroprobot/dragdroprobot_rc.py6
-rw-r--r--examples/widgets/graphicsview/elasticnodes.py413
-rw-r--r--examples/widgets/graphicsview/elasticnodes/elasticnodes.py391
-rw-r--r--examples/widgets/graphicsview/elasticnodes/elasticnodes.pyproject3
-rw-r--r--examples/widgets/graphicsview/graphicsview.pyproject3
16 files changed, 1558 insertions, 1744 deletions
diff --git a/examples/widgets/graphicsview/anchorlayout.py b/examples/widgets/graphicsview/anchorlayout.py
deleted file mode 100644
index f7f4edc65..000000000
--- a/examples/widgets/graphicsview/anchorlayout.py
+++ /dev/null
@@ -1,125 +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$
-##
-#############################################################################
-
-from PySide2 import QtCore, QtWidgets
-
-
-def createItem(minimum, preferred, maximum, name):
- w = QtWidgets.QGraphicsProxyWidget()
-
- w.setWidget(QtWidgets.QPushButton(name))
- w.setMinimumSize(minimum)
- w.setPreferredSize(preferred)
- w.setMaximumSize(maximum)
- w.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
-
- return w
-
-
-if __name__ == '__main__':
-
- import sys
-
- app = QtWidgets.QApplication(sys.argv)
-
- scene = QtWidgets.QGraphicsScene()
- scene.setSceneRect(0, 0, 800, 480)
-
- minSize = QtCore.QSizeF(30, 100)
- prefSize = QtCore.QSizeF(210, 100)
- maxSize = QtCore.QSizeF(300, 100)
-
- a = createItem(minSize, prefSize, maxSize, "A")
- b = createItem(minSize, prefSize, maxSize, "B")
- c = createItem(minSize, prefSize, maxSize, "C")
- d = createItem(minSize, prefSize, maxSize, "D")
- e = createItem(minSize, prefSize, maxSize, "E")
- f = createItem(QtCore.QSizeF(30, 50), QtCore.QSizeF(150, 50), maxSize, "F")
- g = createItem(QtCore.QSizeF(30, 50), QtCore.QSizeF(30, 100), maxSize, "G")
-
- l = QtWidgets.QGraphicsAnchorLayout()
- l.setSpacing(0)
-
- w = QtWidgets.QGraphicsWidget(None, QtCore.Qt.Window)
- w.setPos(20, 20)
- w.setLayout(l)
-
- # Vertical.
- l.addAnchor(a, QtCore.Qt.AnchorTop, l, QtCore.Qt.AnchorTop)
- l.addAnchor(b, QtCore.Qt.AnchorTop, l, QtCore.Qt.AnchorTop)
-
- l.addAnchor(c, QtCore.Qt.AnchorTop, a, QtCore.Qt.AnchorBottom)
- l.addAnchor(c, QtCore.Qt.AnchorTop, b, QtCore.Qt.AnchorBottom)
- l.addAnchor(c, QtCore.Qt.AnchorBottom, d, QtCore.Qt.AnchorTop)
- l.addAnchor(c, QtCore.Qt.AnchorBottom, e, QtCore.Qt.AnchorTop)
-
- l.addAnchor(d, QtCore.Qt.AnchorBottom, l, QtCore.Qt.AnchorBottom)
- l.addAnchor(e, QtCore.Qt.AnchorBottom, l, QtCore.Qt.AnchorBottom)
-
- l.addAnchor(c, QtCore.Qt.AnchorTop, f, QtCore.Qt.AnchorTop)
- l.addAnchor(c, QtCore.Qt.AnchorVerticalCenter, f, QtCore.Qt.AnchorBottom)
- l.addAnchor(f, QtCore.Qt.AnchorBottom, g, QtCore.Qt.AnchorTop)
- l.addAnchor(c, QtCore.Qt.AnchorBottom, g, QtCore.Qt.AnchorBottom)
-
- # Horizontal.
- l.addAnchor(l, QtCore.Qt.AnchorLeft, a, QtCore.Qt.AnchorLeft)
- l.addAnchor(l, QtCore.Qt.AnchorLeft, d, QtCore.Qt.AnchorLeft)
- l.addAnchor(a, QtCore.Qt.AnchorRight, b, QtCore.Qt.AnchorLeft)
-
- l.addAnchor(a, QtCore.Qt.AnchorRight, c, QtCore.Qt.AnchorLeft)
- l.addAnchor(c, QtCore.Qt.AnchorRight, e, QtCore.Qt.AnchorLeft)
-
- l.addAnchor(b, QtCore.Qt.AnchorRight, l, QtCore.Qt.AnchorRight)
- l.addAnchor(e, QtCore.Qt.AnchorRight, l, QtCore.Qt.AnchorRight)
- l.addAnchor(d, QtCore.Qt.AnchorRight, e, QtCore.Qt.AnchorLeft)
-
- l.addAnchor(l, QtCore.Qt.AnchorLeft, f, QtCore.Qt.AnchorLeft)
- l.addAnchor(l, QtCore.Qt.AnchorLeft, g, QtCore.Qt.AnchorLeft)
- l.addAnchor(f, QtCore.Qt.AnchorRight, g, QtCore.Qt.AnchorRight)
-
- scene.addItem(w)
- scene.setBackgroundBrush(QtCore.Qt.darkGreen)
-
- view = QtWidgets.QGraphicsView(scene)
- view.show()
-
- sys.exit(app.exec_())
diff --git a/examples/widgets/graphicsview/anchorlayout/anchorlayout.py b/examples/widgets/graphicsview/anchorlayout/anchorlayout.py
new file mode 100644
index 000000000..9d9be041f
--- /dev/null
+++ b/examples/widgets/graphicsview/anchorlayout/anchorlayout.py
@@ -0,0 +1,90 @@
+# Copyright (C) 2013 Riverbank Computing Limited.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+
+from PySide6.QtCore import QSizeF, Qt
+from PySide6.QtWidgets import (QApplication, QGraphicsAnchorLayout,
+ QGraphicsProxyWidget, QGraphicsScene,
+ QGraphicsView, QGraphicsWidget,
+ QPushButton, QSizePolicy)
+
+
+def create_item(minimum, preferred, maximum, name):
+ w = QGraphicsProxyWidget()
+
+ w.setWidget(QPushButton(name))
+ w.setMinimumSize(minimum)
+ w.setPreferredSize(preferred)
+ w.setMaximumSize(maximum)
+ w.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+
+ return w
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+
+ scene = QGraphicsScene()
+ scene.setSceneRect(0, 0, 800, 480)
+
+ min_size = QSizeF(30, 100)
+ pref_size = QSizeF(210, 100)
+ max_size = QSizeF(300, 100)
+
+ a = create_item(min_size, pref_size, max_size, "A")
+ b = create_item(min_size, pref_size, max_size, "B")
+ c = create_item(min_size, pref_size, max_size, "C")
+ d = create_item(min_size, pref_size, max_size, "D")
+ e = create_item(min_size, pref_size, max_size, "E")
+ f = create_item(QSizeF(30, 50), QSizeF(150, 50), max_size, "F")
+ g = create_item(QSizeF(30, 50), QSizeF(30, 100), max_size, "G")
+
+ l = QGraphicsAnchorLayout() # noqa: E741
+ l.setSpacing(0)
+
+ w = QGraphicsWidget(None, Qt.Window)
+ w.setPos(20, 20)
+ w.setLayout(l)
+
+ # Vertical.
+ l.addAnchor(a, Qt.AnchorTop, l, Qt.AnchorTop)
+ l.addAnchor(b, Qt.AnchorTop, l, Qt.AnchorTop)
+
+ l.addAnchor(c, Qt.AnchorTop, a, Qt.AnchorBottom)
+ l.addAnchor(c, Qt.AnchorTop, b, Qt.AnchorBottom)
+ l.addAnchor(c, Qt.AnchorBottom, d, Qt.AnchorTop)
+ l.addAnchor(c, Qt.AnchorBottom, e, Qt.AnchorTop)
+
+ l.addAnchor(d, Qt.AnchorBottom, l, Qt.AnchorBottom)
+ l.addAnchor(e, Qt.AnchorBottom, l, Qt.AnchorBottom)
+
+ l.addAnchor(c, Qt.AnchorTop, f, Qt.AnchorTop)
+ l.addAnchor(c, Qt.AnchorVerticalCenter, f, Qt.AnchorBottom)
+ l.addAnchor(f, Qt.AnchorBottom, g, Qt.AnchorTop)
+ l.addAnchor(c, Qt.AnchorBottom, g, Qt.AnchorBottom)
+
+ # Horizontal.
+ l.addAnchor(l, Qt.AnchorLeft, a, Qt.AnchorLeft)
+ l.addAnchor(l, Qt.AnchorLeft, d, Qt.AnchorLeft)
+ l.addAnchor(a, Qt.AnchorRight, b, Qt.AnchorLeft)
+
+ l.addAnchor(a, Qt.AnchorRight, c, Qt.AnchorLeft)
+ l.addAnchor(c, Qt.AnchorRight, e, Qt.AnchorLeft)
+
+ l.addAnchor(b, Qt.AnchorRight, l, Qt.AnchorRight)
+ l.addAnchor(e, Qt.AnchorRight, l, Qt.AnchorRight)
+ l.addAnchor(d, Qt.AnchorRight, e, Qt.AnchorLeft)
+
+ l.addAnchor(l, Qt.AnchorLeft, f, Qt.AnchorLeft)
+ l.addAnchor(l, Qt.AnchorLeft, g, Qt.AnchorLeft)
+ l.addAnchor(f, Qt.AnchorRight, g, Qt.AnchorRight)
+
+ scene.addItem(w)
+ scene.setBackgroundBrush(Qt.darkGreen)
+
+ view = QGraphicsView(scene)
+ view.show()
+
+ sys.exit(app.exec())
diff --git a/examples/widgets/graphicsview/anchorlayout/anchorlayout.pyproject b/examples/widgets/graphicsview/anchorlayout/anchorlayout.pyproject
new file mode 100644
index 000000000..49ed7b734
--- /dev/null
+++ b/examples/widgets/graphicsview/anchorlayout/anchorlayout.pyproject
@@ -0,0 +1,3 @@
+{
+ "files": ["anchorlayout.py"]
+}
diff --git a/examples/widgets/graphicsview/collidingmice/collidingmice.py b/examples/widgets/graphicsview/collidingmice/collidingmice.py
index 08a62d0e0..fb24db3ab 100644
--- a/examples/widgets/graphicsview/collidingmice/collidingmice.py
+++ b/examples/widgets/graphicsview/collidingmice/collidingmice.py
@@ -1,93 +1,53 @@
-
-#############################################################################
-##
-## 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$
-##
-#############################################################################
+# Copyright (C) 2013 Riverbank Computing Limited.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import math
+import sys
+
+from PySide6.QtCore import (QLineF, QPointF, QRandomGenerator, QRectF, QTimer, Qt)
+from PySide6.QtGui import (QBrush, QColor, QPainter, QPainterPath, QPixmap, QPolygonF, QTransform)
+from PySide6.QtWidgets import (QApplication, QGraphicsItem, QGraphicsScene, QGraphicsView)
-from PySide2 import QtCore, QtGui, QtWidgets
+import mice_rc # noqa: F401
-import mice_rc
+def random(boundary):
+ return QRandomGenerator.global_().bounded(boundary)
-class Mouse(QtWidgets.QGraphicsItem):
- Pi = math.pi
- TwoPi = 2.0 * Pi
+
+class Mouse(QGraphicsItem):
+ PI = math.pi
+ TWO_PI = 2.0 * PI
# Create the bounding rectangle once.
adjust = 0.5
- BoundingRect = QtCore.QRectF(-20 - adjust, -22 - adjust, 40 + adjust,
- 83 + adjust)
+ BOUNDING_RECT = QRectF(-20 - adjust, -22 - adjust, 40 + adjust,
+ 83 + adjust)
def __init__(self):
- super(Mouse, self).__init__()
+ super().__init__()
self.angle = 0.0
self.speed = 0.0
- self.mouseEyeDirection = 0.0
- self.color = QtGui.QColor(QtCore.qrand() % 256, QtCore.qrand() % 256,
- QtCore.qrand() % 256)
-
- self.setTransform(QtGui.QTransform().rotate(QtCore.qrand() % (360 * 16)))
+ self._mouse_eye_direction = 0.0
+ self.color = QColor(random(256), random(256), random(256))
- # In the C++ version of this example, this class is also derived from
- # QObject in order to receive timer events. PySide2 does not support
- # deriving from more than one wrapped class so we just create an
- # explicit timer instead.
- self.timer = QtCore.QTimer()
- self.timer.timeout.connect(self.timerEvent)
- self.timer.start(1000 / 33)
+ self.setTransform(QTransform().rotate(random(360 * 16)))
@staticmethod
- def normalizeAngle(angle):
+ def normalize_angle(angle):
while angle < 0:
- angle += Mouse.TwoPi
- while angle > Mouse.TwoPi:
- angle -= Mouse.TwoPi
+ angle += Mouse.TWO_PI
+ while angle > Mouse.TWO_PI:
+ angle -= Mouse.TWO_PI
return angle
def boundingRect(self):
- return Mouse.BoundingRect
+ return Mouse.BOUNDING_RECT
def shape(self):
- path = QtGui.QPainterPath()
+ path = QPainterPath()
path.addRect(-10, -20, 20, 40)
return path
@@ -97,120 +57,122 @@ class Mouse(QtWidgets.QGraphicsItem):
painter.drawEllipse(-10, -20, 20, 40)
# Eyes.
- painter.setBrush(QtCore.Qt.white)
+ painter.setBrush(Qt.white)
painter.drawEllipse(-10, -17, 8, 8)
painter.drawEllipse(2, -17, 8, 8)
# Nose.
- painter.setBrush(QtCore.Qt.black)
- painter.drawEllipse(QtCore.QRectF(-2, -22, 4, 4))
+ painter.setBrush(Qt.black)
+ painter.drawEllipse(QRectF(-2, -22, 4, 4))
# Pupils.
- painter.drawEllipse(QtCore.QRectF(-8.0 + self.mouseEyeDirection, -17, 4, 4))
- painter.drawEllipse(QtCore.QRectF(4.0 + self.mouseEyeDirection, -17, 4, 4))
+ painter.drawEllipse(QRectF(-8.0 + self._mouse_eye_direction, -17, 4, 4))
+ painter.drawEllipse(QRectF(4.0 + self._mouse_eye_direction, -17, 4, 4))
# Ears.
if self.scene().collidingItems(self):
- painter.setBrush(QtCore.Qt.red)
+ painter.setBrush(Qt.red)
else:
- painter.setBrush(QtCore.Qt.darkYellow)
+ painter.setBrush(Qt.darkYellow)
painter.drawEllipse(-17, -12, 16, 16)
painter.drawEllipse(1, -12, 16, 16)
# Tail.
- path = QtGui.QPainterPath(QtCore.QPointF(0, 20))
+ path = QPainterPath(QPointF(0, 20))
path.cubicTo(-5, 22, -5, 22, 0, 25)
path.cubicTo(5, 27, 5, 32, 0, 30)
path.cubicTo(-5, 32, -5, 42, 0, 35)
- painter.setBrush(QtCore.Qt.NoBrush)
+ painter.setBrush(Qt.NoBrush)
painter.drawPath(path)
- def timerEvent(self):
+ def advance(self, phase):
+ if not phase:
+ return
# Don't move too far away.
- lineToCenter = QtCore.QLineF(QtCore.QPointF(0, 0), self.mapFromScene(0, 0))
- if lineToCenter.length() > 150:
- angleToCenter = math.acos(lineToCenter.dx() / lineToCenter.length())
- if lineToCenter.dy() < 0:
- angleToCenter = Mouse.TwoPi - angleToCenter
- angleToCenter = Mouse.normalizeAngle((Mouse.Pi - angleToCenter) + Mouse.Pi / 2)
-
- if angleToCenter < Mouse.Pi and angleToCenter > Mouse.Pi / 4:
+ line_to_center = QLineF(QPointF(0, 0), self.mapFromScene(0, 0))
+ if line_to_center.length() > 150:
+ angle_to_center = math.acos(line_to_center.dx() / line_to_center.length())
+ if line_to_center.dy() < 0:
+ angle_to_center = Mouse.TWO_PI - angle_to_center
+ angle_to_center = Mouse.normalize_angle((Mouse.PI - angle_to_center) + Mouse.PI / 2)
+
+ if angle_to_center < Mouse.PI and angle_to_center > Mouse.PI / 4:
# Rotate left.
- self.angle += [-0.25, 0.25][self.angle < -Mouse.Pi / 2]
- elif angleToCenter >= Mouse.Pi and angleToCenter < (Mouse.Pi + Mouse.Pi / 2 + Mouse.Pi / 4):
+ self.angle += [-0.25, 0.25][self.angle < -Mouse.PI / 2]
+ elif (angle_to_center >= Mouse.PI
+ and angle_to_center < (Mouse.PI + Mouse.PI / 2 + Mouse.PI / 4)):
# Rotate right.
- self.angle += [-0.25, 0.25][self.angle < Mouse.Pi / 2]
+ self.angle += [-0.25, 0.25][self.angle < Mouse.PI / 2]
elif math.sin(self.angle) < 0:
self.angle += 0.25
elif math.sin(self.angle) > 0:
self.angle -= 0.25
# Try not to crash with any other mice.
- dangerMice = self.scene().items(QtGui.QPolygonF([self.mapToScene(0, 0),
- self.mapToScene(-30, -50),
- self.mapToScene(30, -50)]))
+ danger_mice = self.scene().items(QPolygonF([self.mapToScene(0, 0),
+ self.mapToScene(-30, -50),
+ self.mapToScene(30, -50)]))
- for item in dangerMice:
+ for item in danger_mice:
if item is self:
continue
- lineToMouse = QtCore.QLineF(QtCore.QPointF(0, 0), self.mapFromItem(item, 0, 0))
- angleToMouse = math.acos(lineToMouse.dx() / lineToMouse.length())
- if lineToMouse.dy() < 0:
- angleToMouse = Mouse.TwoPi - angleToMouse
- angleToMouse = Mouse.normalizeAngle((Mouse.Pi - angleToMouse) + Mouse.Pi / 2)
+ line_to_mouse = QLineF(QPointF(0, 0), self.mapFromItem(item, 0, 0))
+ angle_to_mouse = math.acos(line_to_mouse.dx() / line_to_mouse.length())
+ if line_to_mouse.dy() < 0:
+ angle_to_mouse = Mouse.TWO_PI - angle_to_mouse
+ angle_to_mouse = Mouse.normalize_angle((Mouse.PI - angle_to_mouse) + Mouse.PI / 2)
- if angleToMouse >= 0 and angleToMouse < Mouse.Pi / 2:
+ if angle_to_mouse >= 0 and angle_to_mouse < Mouse.PI / 2:
# Rotate right.
self.angle += 0.5
- elif angleToMouse <= Mouse.TwoPi and angleToMouse > (Mouse.TwoPi - Mouse.Pi / 2):
+ elif angle_to_mouse <= Mouse.TWO_PI and angle_to_mouse > (Mouse.TWO_PI - Mouse.PI / 2):
# Rotate left.
self.angle -= 0.5
# Add some random movement.
- if len(dangerMice) > 1 and (QtCore.qrand() % 10) == 0:
- if QtCore.qrand() % 1:
- self.angle += (QtCore.qrand() % 100) / 500.0
+ if len(danger_mice) > 1 and random(10) == 0:
+ if random(2) != 0:
+ self.angle += random(100) / 500.0
else:
- self.angle -= (QtCore.qrand() % 100) / 500.0
+ self.angle -= random(100) / 500.0
- self.speed += (-50 + QtCore.qrand() % 100) / 100.0
+ self.speed += (-50 + random(100)) / 100.0
dx = math.sin(self.angle) * 10
- self.mouseEyeDirection = [dx / 5, 0.0][QtCore.qAbs(dx / 5) < 1]
- self.setTransform(QtGui.QTransform().rotate(dx))
+ self._mouse_eye_direction = [dx / 5, 0.0][abs(dx / 5) < 1]
+
+ self.setRotation(self.rotation() + dx)
self.setPos(self.mapToParent(0, -(3 + math.sin(self.speed) * 3)))
if __name__ == '__main__':
+ MOUSE_COUNT = 7
+ app = QApplication(sys.argv)
- import sys
-
- MouseCount = 7
-
- app = QtWidgets.QApplication(sys.argv)
- QtCore.qsrand(QtCore.QTime(0,0,0).secsTo(QtCore.QTime.currentTime()))
-
- scene = QtWidgets.QGraphicsScene()
+ scene = QGraphicsScene()
scene.setSceneRect(-300, -300, 600, 600)
- scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
+ scene.setItemIndexMethod(QGraphicsScene.NoIndex)
- for i in range(MouseCount):
+ for i in range(MOUSE_COUNT):
mouse = Mouse()
- mouse.setPos(math.sin((i * 6.28) / MouseCount) * 200,
- math.cos((i * 6.28) / MouseCount) * 200)
+ mouse.setPos(math.sin((i * 6.28) / MOUSE_COUNT) * 200,
+ math.cos((i * 6.28) / MOUSE_COUNT) * 200)
scene.addItem(mouse)
- view = QtWidgets.QGraphicsView(scene)
- view.setRenderHint(QtGui.QPainter.Antialiasing)
- view.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/cheese.jpg')))
- view.setCacheMode(QtWidgets.QGraphicsView.CacheBackground)
- view.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate)
- view.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
+ view = QGraphicsView(scene)
+ view.setRenderHint(QPainter.Antialiasing)
+ view.setBackgroundBrush(QBrush(QPixmap(':/images/cheese.jpg')))
+ view.setCacheMode(QGraphicsView.CacheBackground)
+ view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
+ view.setDragMode(QGraphicsView.ScrollHandDrag)
view.setWindowTitle("Colliding Mice")
view.resize(400, 300)
view.show()
- sys.exit(app.exec_())
+ timer = QTimer()
+ timer.timeout.connect(scene.advance)
+ timer.start(1000 / 33)
+ sys.exit(app.exec())
diff --git a/examples/widgets/graphicsview/collidingmice/collidingmice.pyproject b/examples/widgets/graphicsview/collidingmice/collidingmice.pyproject
index ea5821866..621bfd642 100644
--- a/examples/widgets/graphicsview/collidingmice/collidingmice.pyproject
+++ b/examples/widgets/graphicsview/collidingmice/collidingmice.pyproject
@@ -1,3 +1,3 @@
{
- "files": ["collidingmice.py", "mice_rc.py"]
+ "files": ["collidingmice.py"]
}
diff --git a/examples/widgets/graphicsview/collidingmice/mice_rc.py b/examples/widgets/graphicsview/collidingmice/mice_rc.py
index e9042a0d9..e2a22b2e4 100644
--- a/examples/widgets/graphicsview/collidingmice/mice_rc.py
+++ b/examples/widgets/graphicsview/collidingmice/mice_rc.py
@@ -1,45 +1,6 @@
-# -*- coding: utf-8 -*-
-
-#############################################################################
-##
-## 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$
-##
-#############################################################################
+# Copyright (C) 2013 Riverbank Computing Limited.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
# Resource object code
#
@@ -48,7 +9,7 @@
#
# WARNING! All changes made in this file will be lost!
-from PySide2 import QtCore
+from PySide6 import QtCore
qt_resource_data = b"\
\x00\x00\x0b\xd5\
diff --git a/examples/widgets/graphicsview/diagramscene/diagramscene.py b/examples/widgets/graphicsview/diagramscene/diagramscene.py
index 3890782c4..60e05613c 100644
--- a/examples/widgets/graphicsview/diagramscene/diagramscene.py
+++ b/examples/widgets/graphicsview/diagramscene/diagramscene.py
@@ -1,300 +1,276 @@
-
-#############################################################################
-##
-## 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$
-##
-#############################################################################
+# Copyright (C) 2013 Riverbank Computing Limited.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import math
+import sys
-from PySide2 import QtCore, QtGui, QtWidgets
+from PySide6.QtCore import (QLineF, QPointF, QRect, QRectF, QSize, QSizeF, Qt,
+ Signal, Slot)
+from PySide6.QtGui import (QAction, QBrush, QColor, QFont, QIcon, QIntValidator,
+ QPainter, QPainterPath, QPen, QPixmap, QPolygonF)
+from PySide6.QtWidgets import (QAbstractButton, QApplication, QButtonGroup,
+ QComboBox, QFontComboBox, QGraphicsItem, QGraphicsLineItem,
+ QGraphicsPolygonItem, QGraphicsTextItem,
+ QGraphicsScene, QGraphicsView, QGridLayout,
+ QHBoxLayout, QLabel, QMainWindow, QMenu,
+ QMessageBox, QSizePolicy, QToolBox, QToolButton,
+ QWidget)
-import diagramscene_rc
+import diagramscene_rc # noqa: F401
-class Arrow(QtWidgets.QGraphicsLineItem):
+class Arrow(QGraphicsLineItem):
def __init__(self, startItem, endItem, parent=None, scene=None):
- super(Arrow, self).__init__(parent, scene)
+ super().__init__(parent, scene)
- self.arrowHead = QtGui.QPolygonF()
+ self._arrow_head = QPolygonF()
- self.myStartItem = startItem
- self.myEndItem = endItem
- self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
- self.myColor = QtCore.Qt.black
- self.setPen(QtGui.QPen(self.myColor, 2, QtCore.Qt.SolidLine,
- QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
+ self._my_start_item = startItem
+ self._my_end_item = endItem
+ self.setFlag(QGraphicsItem.ItemIsSelectable, True)
+ self._my_color = Qt.black
+ self.setPen(QPen(self._my_color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
- def setColor(self, color):
- self.myColor = color
+ def set_color(self, color):
+ self._my_color = color
- def startItem(self):
- return self.myStartItem
+ def start_item(self):
+ return self._my_start_item
- def endItem(self):
- return self.myEndItem
+ def end_item(self):
+ return self._my_end_item
def boundingRect(self):
extra = (self.pen().width() + 20) / 2.0
p1 = self.line().p1()
p2 = self.line().p2()
- return QtCore.QRectF(p1, QtCore.QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted(-extra, -extra, extra, extra)
+ rect = QRectF(p1, QSizeF(p2.x() - p1.x(), p2.y() - p1.y()))
+ return rect.normalized().adjusted(-extra, -extra, extra, extra)
def shape(self):
path = super(Arrow, self).shape()
- path.addPolygon(self.arrowHead)
+ path.addPolygon(self._arrow_head)
return path
- def updatePosition(self):
- line = QtCore.QLineF(self.mapFromItem(self.myStartItem, 0, 0), self.mapFromItem(self.myEndItem, 0, 0))
- self.setLine(line)
+ def update_position(self):
+ start = self.mapFromItem(self._my_start_item, 0, 0)
+ end = self.mapFromItem(self._my_end_item, 0, 0)
+ self.setLine(QLineF(start, end))
def paint(self, painter, option, widget=None):
- if (self.myStartItem.collidesWithItem(self.myEndItem)):
+ if (self._my_start_item.collidesWithItem(self._my_end_item)):
return
- myStartItem = self.myStartItem
- myEndItem = self.myEndItem
- myColor = self.myColor
- myPen = self.pen()
- myPen.setColor(self.myColor)
- arrowSize = 20.0
- painter.setPen(myPen)
- painter.setBrush(self.myColor)
-
- centerLine = QtCore.QLineF(myStartItem.pos(), myEndItem.pos())
- endPolygon = myEndItem.polygon()
- p1 = endPolygon.at(0) + myEndItem.pos()
-
- intersectPoint = QtCore.QPointF()
- for i in endPolygon:
- p2 = i + myEndItem.pos()
- polyLine = QtCore.QLineF(p1, p2)
- intersectType, intersectPoint = polyLine.intersect(centerLine)
- if intersectType == QtCore.QLineF.BoundedIntersection:
+ my_start_item = self._my_start_item
+ my_end_item = self._my_end_item
+ my_color = self._my_color
+ my_pen = self.pen()
+ my_pen.setColor(self._my_color)
+ arrow_size = 20.0
+ painter.setPen(my_pen)
+ painter.setBrush(self._my_color)
+
+ center_line = QLineF(my_start_item.pos(), my_end_item.pos())
+ end_polygon = my_end_item.polygon()
+ p1 = end_polygon.at(0) + my_end_item.pos()
+
+ intersect_point = QPointF()
+ for i in end_polygon:
+ p2 = i + my_end_item.pos()
+ poly_line = QLineF(p1, p2)
+ intersectType, intersect_point = poly_line.intersects(center_line)
+ if intersectType == QLineF.BoundedIntersection:
break
p1 = p2
- self.setLine(QtCore.QLineF(intersectPoint, myStartItem.pos()))
+ self.setLine(QLineF(intersect_point, my_start_item.pos()))
line = self.line()
angle = math.acos(line.dx() / line.length())
if line.dy() >= 0:
angle = (math.pi * 2.0) - angle
- arrowP1 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi / 3.0) * arrowSize,
- math.cos(angle + math.pi / 3) * arrowSize)
- arrowP2 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrowSize,
- math.cos(angle + math.pi - math.pi / 3.0) * arrowSize)
+ arrow_head1 = QPointF(math.sin(angle + math.pi / 3.0) * arrow_size,
+ math.cos(angle + math.pi / 3) * arrow_size)
+ arrow_p1 = line.p1() + arrow_head1
+ arrow_head2 = QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrow_size,
+ math.cos(angle + math.pi - math.pi / 3.0) * arrow_size)
+ arrow_p2 = line.p1() + arrow_head2
- self.arrowHead.clear()
- for point in [line.p1(), arrowP1, arrowP2]:
- self.arrowHead.append(point)
+ self._arrow_head.clear()
+ for point in [line.p1(), arrow_p1, arrow_p2]:
+ self._arrow_head.append(point)
painter.drawLine(line)
- painter.drawPolygon(self.arrowHead)
+ painter.drawPolygon(self._arrow_head)
if self.isSelected():
- painter.setPen(QtGui.QPen(myColor, 1, QtCore.Qt.DashLine))
- myLine = QtCore.QLineF(line)
- myLine.translate(0, 4.0)
- painter.drawLine(myLine)
- myLine.translate(0,-8.0)
- painter.drawLine(myLine)
+ painter.setPen(QPen(my_color, 1, Qt.DashLine))
+ my_line = QLineF(line)
+ my_line.translate(0, 4.0)
+ painter.drawLine(my_line)
+ my_line.translate(0, -8.0)
+ painter.drawLine(my_line)
-class DiagramTextItem(QtWidgets.QGraphicsTextItem):
- lostFocus = QtCore.Signal(QtWidgets.QGraphicsTextItem)
+class DiagramTextItem(QGraphicsTextItem):
+ lost_focus = Signal(QGraphicsTextItem)
- selectedChange = QtCore.Signal(QtWidgets.QGraphicsItem)
+ selected_change = Signal(QGraphicsItem)
def __init__(self, parent=None, scene=None):
- super(DiagramTextItem, self).__init__(parent, scene)
+ super().__init__(parent, scene)
- self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
- self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable)
+ self.setFlag(QGraphicsItem.ItemIsMovable)
+ self.setFlag(QGraphicsItem.ItemIsSelectable)
def itemChange(self, change, value):
- if change == QtWidgets.QGraphicsItem.ItemSelectedChange:
- self.selectedChange.emit(self)
+ if change == QGraphicsItem.ItemSelectedChange:
+ self.selected_change.emit(self)
return value
def focusOutEvent(self, event):
- self.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
- self.lostFocus.emit(self)
+ self.setTextInteractionFlags(Qt.NoTextInteraction)
+ self.lost_focus.emit(self)
super(DiagramTextItem, self).focusOutEvent(event)
def mouseDoubleClickEvent(self, event):
- if self.textInteractionFlags() == QtCore.Qt.NoTextInteraction:
- self.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
+ if self.textInteractionFlags() == Qt.NoTextInteraction:
+ self.setTextInteractionFlags(Qt.TextEditorInteraction)
super(DiagramTextItem, self).mouseDoubleClickEvent(event)
-class DiagramItem(QtWidgets.QGraphicsPolygonItem):
+class DiagramItem(QGraphicsPolygonItem):
Step, Conditional, StartEnd, Io = range(4)
- def __init__(self, diagramType, contextMenu, parent=None, scene=None):
- super(DiagramItem, self).__init__(parent, scene)
+ def __init__(self, diagram_type, contextMenu, parent=None, scene=None):
+ super().__init__(parent, scene)
self.arrows = []
- self.diagramType = diagramType
- self.myContextMenu = contextMenu
+ self.diagram_type = diagram_type
+ self._my_context_menu = contextMenu
- path = QtGui.QPainterPath()
- if self.diagramType == self.StartEnd:
+ path = QPainterPath()
+ if self.diagram_type == self.StartEnd:
path.moveTo(200, 50)
path.arcTo(150, 0, 50, 50, 0, 90)
path.arcTo(50, 0, 50, 50, 90, 90)
path.arcTo(50, 50, 50, 50, 180, 90)
path.arcTo(150, 50, 50, 50, 270, 90)
path.lineTo(200, 25)
- self.myPolygon = path.toFillPolygon()
- elif self.diagramType == self.Conditional:
- self.myPolygon = QtGui.QPolygonF([
- QtCore.QPointF(-100, 0), QtCore.QPointF(0, 100),
- QtCore.QPointF(100, 0), QtCore.QPointF(0, -100),
- QtCore.QPointF(-100, 0)])
- elif self.diagramType == self.Step:
- self.myPolygon = QtGui.QPolygonF([
- QtCore.QPointF(-100, -100), QtCore.QPointF(100, -100),
- QtCore.QPointF(100, 100), QtCore.QPointF(-100, 100),
- QtCore.QPointF(-100, -100)])
+ self._my_polygon = path.toFillPolygon()
+ elif self.diagram_type == self.Conditional:
+ self._my_polygon = QPolygonF([
+ QPointF(-100, 0), QPointF(0, 100),
+ QPointF(100, 0), QPointF(0, -100),
+ QPointF(-100, 0)])
+ elif self.diagram_type == self.Step:
+ self._my_polygon = QPolygonF([
+ QPointF(-100, -100), QPointF(100, -100),
+ QPointF(100, 100), QPointF(-100, 100),
+ QPointF(-100, -100)])
else:
- self.myPolygon = QtGui.QPolygonF([
- QtCore.QPointF(-120, -80), QtCore.QPointF(-70, 80),
- QtCore.QPointF(120, 80), QtCore.QPointF(70, -80),
- QtCore.QPointF(-120, -80)])
+ self._my_polygon = QPolygonF([
+ QPointF(-120, -80), QPointF(-70, 80),
+ QPointF(120, 80), QPointF(70, -80),
+ QPointF(-120, -80)])
- self.setPolygon(self.myPolygon)
- self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
- self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
+ self.setPolygon(self._my_polygon)
+ self.setFlag(QGraphicsItem.ItemIsMovable, True)
+ self.setFlag(QGraphicsItem.ItemIsSelectable, True)
- def removeArrow(self, arrow):
+ def remove_arrow(self, arrow):
try:
self.arrows.remove(arrow)
except ValueError:
pass
- def removeArrows(self):
+ def remove_arrows(self):
for arrow in self.arrows[:]:
- arrow.startItem().removeArrow(arrow)
- arrow.endItem().removeArrow(arrow)
+ arrow.start_item().remove_arrow(arrow)
+ arrow.end_item().remove_arrow(arrow)
self.scene().removeItem(arrow)
- def addArrow(self, arrow):
+ def add_arrow(self, arrow):
self.arrows.append(arrow)
def image(self):
- pixmap = QtGui.QPixmap(250, 250)
- pixmap.fill(QtCore.Qt.transparent)
- painter = QtGui.QPainter(pixmap)
- painter.setPen(QtGui.QPen(QtCore.Qt.black, 8))
- painter.translate(125, 125)
- painter.drawPolyline(self.myPolygon)
+ pixmap = QPixmap(250, 250)
+ pixmap.fill(Qt.transparent)
+ with QPainter(pixmap) as painter:
+ painter.setPen(QPen(Qt.black, 8))
+ painter.translate(125, 125)
+ painter.drawPolyline(self._my_polygon)
return pixmap
def contextMenuEvent(self, event):
self.scene().clearSelection()
self.setSelected(True)
- self.myContextMenu.exec_(event.screenPos())
+ self._my_context_menu.exec(event.screenPos())
def itemChange(self, change, value):
- if change == QtWidgets.QGraphicsItem.ItemPositionChange:
+ if change == QGraphicsItem.ItemPositionChange:
for arrow in self.arrows:
arrow.updatePosition()
return value
-class DiagramScene(QtWidgets.QGraphicsScene):
- InsertItem, InsertLine, InsertText, MoveItem = range(4)
+class DiagramScene(QGraphicsScene):
+ InsertItem, InsertLine, InsertText, MoveItem = range(4)
- itemInserted = QtCore.Signal(DiagramItem)
+ item_inserted = Signal(DiagramItem)
- textInserted = QtCore.Signal(QtWidgets.QGraphicsTextItem)
+ text_inserted = Signal(QGraphicsTextItem)
- itemSelected = QtCore.Signal(QtWidgets.QGraphicsItem)
+ item_selected = Signal(QGraphicsItem)
def __init__(self, itemMenu, parent=None):
- super(DiagramScene, self).__init__(parent)
+ super().__init__(parent)
- self.myItemMenu = itemMenu
- self.myMode = self.MoveItem
- self.myItemType = DiagramItem.Step
+ self._my_item_menu = itemMenu
+ self._my_mode = self.MoveItem
+ self._my_item_type = DiagramItem.Step
self.line = None
- self.textItem = None
- self.myItemColor = QtCore.Qt.white
- self.myTextColor = QtCore.Qt.black
- self.myLineColor = QtCore.Qt.black
- self.myFont = QtGui.QFont()
-
- def setLineColor(self, color):
- self.myLineColor = color
- if self.isItemChange(Arrow):
+ self._text_item = None
+ self._my_item_color = Qt.white
+ self._my_text_color = Qt.black
+ self._my_line_color = Qt.black
+ self._my_font = QFont()
+
+ def set_line_color(self, color):
+ self._my_line_color = color
+ if self.is_item_change(Arrow):
item = self.selectedItems()[0]
- item.setColor(self.myLineColor)
+ item.set_color(self._my_line_color)
self.update()
- def setTextColor(self, color):
- self.myTextColor = color
- if self.isItemChange(DiagramTextItem):
+ def set_text_color(self, color):
+ self._my_text_color = color
+ if self.is_item_change(DiagramTextItem):
item = self.selectedItems()[0]
- item.setDefaultTextColor(self.myTextColor)
+ item.setDefaultTextColor(self._my_text_color)
- def setItemColor(self, color):
- self.myItemColor = color
- if self.isItemChange(DiagramItem):
+ def set_item_color(self, color):
+ self._my_item_color = color
+ if self.is_item_change(DiagramItem):
item = self.selectedItems()[0]
- item.setBrush(self.myItemColor)
+ item.setBrush(self._my_item_color)
- def setFont(self, font):
- self.myFont = font
- if self.isItemChange(DiagramTextItem):
+ def set_font(self, font):
+ self._my_font = font
+ if self.is_item_change(DiagramTextItem):
item = self.selectedItems()[0]
- item.setFont(self.myFont)
+ item.setFont(self._my_font)
- def setMode(self, mode):
- self.myMode = mode
+ def set_mode(self, mode):
+ self._my_mode = mode
- def setItemType(self, type):
- self.myItemType = type
+ def set_item_type(self, type):
+ self._my_item_type = type
- def editorLostFocus(self, item):
+ def editor_lost_focus(self, item):
cursor = item.textCursor()
cursor.clearSelection()
item.setTextCursor(cursor)
@@ -304,521 +280,523 @@ class DiagramScene(QtWidgets.QGraphicsScene):
item.deleteLater()
def mousePressEvent(self, mouseEvent):
- if (mouseEvent.button() != QtCore.Qt.LeftButton):
+ if (mouseEvent.button() != Qt.LeftButton):
return
- if self.myMode == self.InsertItem:
- item = DiagramItem(self.myItemType, self.myItemMenu)
- item.setBrush(self.myItemColor)
+ if self._my_mode == self.InsertItem:
+ item = DiagramItem(self._my_item_type, self._my_item_menu)
+ item.setBrush(self._my_item_color)
self.addItem(item)
item.setPos(mouseEvent.scenePos())
- self.itemInserted.emit(item)
- elif self.myMode == self.InsertLine:
- self.line = QtWidgets.QGraphicsLineItem(QtCore.QLineF(mouseEvent.scenePos(),
- mouseEvent.scenePos()))
- self.line.setPen(QtGui.QPen(self.myLineColor, 2))
+ self.item_inserted.emit(item)
+ elif self._my_mode == self.InsertLine:
+ self.line = QGraphicsLineItem(QLineF(mouseEvent.scenePos(), mouseEvent.scenePos()))
+ self.line.setPen(QPen(self._my_line_color, 2))
self.addItem(self.line)
- elif self.myMode == self.InsertText:
- textItem = DiagramTextItem()
- textItem.setFont(self.myFont)
- textItem.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
- textItem.setZValue(1000.0)
- textItem.lostFocus.connect(self.editorLostFocus)
- textItem.selectedChange.connect(self.itemSelected)
- self.addItem(textItem)
- textItem.setDefaultTextColor(self.myTextColor)
- textItem.setPos(mouseEvent.scenePos())
- self.textInserted.emit(textItem)
+ elif self._my_mode == self.InsertText:
+ text_item = DiagramTextItem()
+ text_item.setFont(self._my_font)
+ text_item.setTextInteractionFlags(Qt.TextEditorInteraction)
+ text_item.setZValue(1000.0)
+ text_item.lost_focus.connect(self.editor_lost_focus)
+ text_item.selected_change.connect(self.item_selected)
+ self.addItem(text_item)
+ text_item.setDefaultTextColor(self._my_text_color)
+ text_item.setPos(mouseEvent.scenePos())
+ self.text_inserted.emit(text_item)
super(DiagramScene, self).mousePressEvent(mouseEvent)
def mouseMoveEvent(self, mouseEvent):
- if self.myMode == self.InsertLine and self.line:
- newLine = QtCore.QLineF(self.line.line().p1(), mouseEvent.scenePos())
- self.line.setLine(newLine)
- elif self.myMode == self.MoveItem:
+ if self._my_mode == self.InsertLine and self.line:
+ new_line = QLineF(self.line.line().p1(), mouseEvent.scenePos())
+ self.line.setLine(new_line)
+ elif self._my_mode == self.MoveItem:
super(DiagramScene, self).mouseMoveEvent(mouseEvent)
def mouseReleaseEvent(self, mouseEvent):
- if self.line and self.myMode == self.InsertLine:
- startItems = self.items(self.line.line().p1())
- if len(startItems) and startItems[0] == self.line:
- startItems.pop(0)
- endItems = self.items(self.line.line().p2())
- if len(endItems) and endItems[0] == self.line:
- endItems.pop(0)
+ if self.line and self._my_mode == self.InsertLine:
+ start_items = self.items(self.line.line().p1())
+ if len(start_items) and start_items[0] == self.line:
+ start_items.pop(0)
+ end_items = self.items(self.line.line().p2())
+ if len(end_items) and end_items[0] == self.line:
+ end_items.pop(0)
self.removeItem(self.line)
self.line = None
- if len(startItems) and len(endItems) and \
- isinstance(startItems[0], DiagramItem) and \
- isinstance(endItems[0], DiagramItem) and \
- startItems[0] != endItems[0]:
- startItem = startItems[0]
- endItem = endItems[0]
- arrow = Arrow(startItem, endItem)
- arrow.setColor(self.myLineColor)
- startItem.addArrow(arrow)
- endItem.addArrow(arrow)
+ if (len(start_items) and len(end_items)
+ and isinstance(start_items[0], DiagramItem)
+ and isinstance(end_items[0], DiagramItem)
+ and start_items[0] != end_items[0]):
+ start_item = start_items[0]
+ end_item = end_items[0]
+ arrow = Arrow(start_item, end_item)
+ arrow.set_color(self._my_line_color)
+ start_item.add_arrow(arrow)
+ end_item.add_arrow(arrow)
arrow.setZValue(-1000.0)
self.addItem(arrow)
- arrow.updatePosition()
+ arrow.update_position()
self.line = None
super(DiagramScene, self).mouseReleaseEvent(mouseEvent)
- def isItemChange(self, type):
+ def is_item_change(self, type):
for item in self.selectedItems():
if isinstance(item, type):
return True
return False
-class MainWindow(QtWidgets.QMainWindow):
- InsertTextButton = 10
+class MainWindow(QMainWindow):
+ insert_text_button = 10
def __init__(self):
- super(MainWindow, self).__init__()
+ super().__init__()
- self.createActions()
- self.createMenus()
- self.createToolBox()
+ self.create_actions()
+ self.create_menus()
+ self.create_tool_box()
- self.scene = DiagramScene(self.itemMenu)
- self.scene.setSceneRect(QtCore.QRectF(0, 0, 5000, 5000))
- self.scene.itemInserted.connect(self.itemInserted)
- self.scene.textInserted.connect(self.textInserted)
- self.scene.itemSelected.connect(self.itemSelected)
+ self.scene = DiagramScene(self._item_menu)
+ self.scene.setSceneRect(QRectF(0, 0, 5000, 5000))
+ self.scene.item_inserted.connect(self.item_inserted)
+ self.scene.text_inserted.connect(self.text_inserted)
+ self.scene.item_selected.connect(self.item_selected)
- self.createToolbars()
+ self.create_toolbars()
- layout = QtWidgets.QHBoxLayout()
- layout.addWidget(self.toolBox)
- self.view = QtWidgets.QGraphicsView(self.scene)
+ layout = QHBoxLayout()
+ layout.addWidget(self._tool_box)
+ self.view = QGraphicsView(self.scene)
layout.addWidget(self.view)
- self.widget = QtWidgets.QWidget()
+ self.widget = QWidget()
self.widget.setLayout(layout)
self.setCentralWidget(self.widget)
self.setWindowTitle("Diagramscene")
- def backgroundButtonGroupClicked(self, button):
- buttons = self.backgroundButtonGroup.buttons()
+ @Slot(QAbstractButton)
+ def background_button_group_clicked(self, button):
+ buttons = self._background_button_group.buttons()
for myButton in buttons:
if myButton != button:
button.setChecked(False)
text = button.text()
if text == "Blue Grid":
- self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background1.png')))
+ self.scene.setBackgroundBrush(QBrush(QPixmap(':/images/background1.png')))
elif text == "White Grid":
- self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background2.png')))
+ self.scene.setBackgroundBrush(QBrush(QPixmap(':/images/background2.png')))
elif text == "Gray Grid":
- self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background3.png')))
+ self.scene.setBackgroundBrush(QBrush(QPixmap(':/images/background3.png')))
else:
- self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background4.png')))
+ self.scene.setBackgroundBrush(QBrush(QPixmap(':/images/background4.png')))
self.scene.update()
self.view.update()
- def buttonGroupClicked(self, id):
- buttons = self.buttonGroup.buttons()
+ @Slot(int)
+ def button_group_clicked(self, idx):
+ buttons = self._button_group.buttons()
for button in buttons:
- if self.buttonGroup.button(id) != button:
+ if self._button_group.button(idx) != button:
button.setChecked(False)
- if id == self.InsertTextButton:
- self.scene.setMode(DiagramScene.InsertText)
+ if idx == self.insert_text_button:
+ self.scene.set_mode(DiagramScene.InsertText)
else:
- self.scene.setItemType(id)
- self.scene.setMode(DiagramScene.InsertItem)
+ self.scene.set_item_type(idx)
+ self.scene.set_mode(DiagramScene.InsertItem)
- def deleteItem(self):
+ @Slot()
+ def delete_item(self):
for item in self.scene.selectedItems():
if isinstance(item, DiagramItem):
- item.removeArrows()
+ item.remove_arrows()
self.scene.removeItem(item)
- def pointerGroupClicked(self, i):
- self.scene.setMode(self.pointerTypeGroup.checkedId())
+ @Slot(int)
+ def pointer_group_clicked(self, i):
+ self.scene.set_mode(self._pointer_type_group.checkedId())
- def bringToFront(self):
+ @Slot()
+ def bring_to_front(self):
if not self.scene.selectedItems():
return
- selectedItem = self.scene.selectedItems()[0]
- overlapItems = selectedItem.collidingItems()
+ selected_item = self.scene.selectedItems()[0]
+ overlap_items = selected_item.collidingItems()
- zValue = 0
- for item in overlapItems:
- if (item.zValue() >= zValue and isinstance(item, DiagramItem)):
- zValue = item.zValue() + 0.1
- selectedItem.setZValue(zValue)
+ z_value = 0
+ for item in overlap_items:
+ if (item.zValue() >= z_value and isinstance(item, DiagramItem)):
+ z_value = item.zValue() + 0.1
+ selected_item.setZValue(z_value)
- def sendToBack(self):
+ @Slot()
+ def send_to_back(self):
if not self.scene.selectedItems():
return
- selectedItem = self.scene.selectedItems()[0]
- overlapItems = selectedItem.collidingItems()
-
- zValue = 0
- for item in overlapItems:
- if (item.zValue() <= zValue and isinstance(item, DiagramItem)):
- zValue = item.zValue() - 0.1
- selectedItem.setZValue(zValue)
-
- def itemInserted(self, item):
- self.pointerTypeGroup.button(DiagramScene.MoveItem).setChecked(True)
- self.scene.setMode(self.pointerTypeGroup.checkedId())
- self.buttonGroup.button(item.diagramType).setChecked(False)
-
- def textInserted(self, item):
- self.buttonGroup.button(self.InsertTextButton).setChecked(False)
- self.scene.setMode(self.pointerTypeGroup.checkedId())
-
- def currentFontChanged(self, font):
- self.handleFontChange()
-
- def fontSizeChanged(self, font):
- self.handleFontChange()
-
- def sceneScaleChanged(self, scale):
- newScale = int(scale[:-1]) / 100.0
- oldMatrix = self.view.matrix()
- self.view.resetMatrix()
- self.view.translate(oldMatrix.dx(), oldMatrix.dy())
- self.view.scale(newScale, newScale)
-
- def textColorChanged(self):
- self.textAction = self.sender()
- self.fontColorToolButton.setIcon(self.createColorToolButtonIcon(
- ':/images/textpointer.png',
- QtGui.QColor(self.textAction.data())))
- self.textButtonTriggered()
-
- def itemColorChanged(self):
- self.fillAction = self.sender()
- self.fillColorToolButton.setIcon(self.createColorToolButtonIcon(
- ':/images/floodfill.png',
- QtGui.QColor(self.fillAction.data())))
- self.fillButtonTriggered()
-
- def lineColorChanged(self):
- self.lineAction = self.sender()
- self.lineColorToolButton.setIcon(self.createColorToolButtonIcon(
- ':/images/linecolor.png',
- QtGui.QColor(self.lineAction.data())))
- self.lineButtonTriggered()
-
- def textButtonTriggered(self):
- self.scene.setTextColor(QtGui.QColor(self.textAction.data()))
-
- def fillButtonTriggered(self):
- self.scene.setItemColor(QtGui.QColor(self.fillAction.data()))
-
- def lineButtonTriggered(self):
- self.scene.setLineColor(QtGui.QColor(self.lineAction.data()))
-
- def handleFontChange(self):
- font = self.fontCombo.currentFont()
- font.setPointSize(int(self.fontSizeCombo.currentText()))
- if self.boldAction.isChecked():
- font.setWeight(QtGui.QFont.Bold)
+ selected_item = self.scene.selectedItems()[0]
+ overlap_items = selected_item.collidingItems()
+
+ z_value = 0
+ for item in overlap_items:
+ if (item.zValue() <= z_value and isinstance(item, DiagramItem)):
+ z_value = item.zValue() - 0.1
+ selected_item.setZValue(z_value)
+
+ @Slot(QGraphicsPolygonItem)
+ def item_inserted(self, item):
+ self._pointer_type_group.button(DiagramScene.MoveItem).setChecked(True)
+ self.scene.set_mode(self._pointer_type_group.checkedId())
+ self._button_group.button(item.diagram_type).setChecked(False)
+
+ @Slot(QGraphicsTextItem)
+ def text_inserted(self, item):
+ self._button_group.button(self.insert_text_button).setChecked(False)
+ self.scene.set_mode(self._pointer_type_group.checkedId())
+
+ @Slot(QFont)
+ def current_font_changed(self, font):
+ self.handle_font_change()
+
+ @Slot(int)
+ def font_size_changed(self, font):
+ self.handle_font_change()
+
+ @Slot(str)
+ def scene_scale_changed(self, scale):
+ new_scale = int(scale[:-1]) / 100.0
+ old_matrix = self.view.transform()
+ self.view.resetTransform()
+ self.view.translate(old_matrix.dx(), old_matrix.dy())
+ self.view.scale(new_scale, new_scale)
+
+ @Slot()
+ def text_color_changed(self):
+ self._text_action = self.sender()
+ self._font_color_tool_button.setIcon(self.create_color_tool_button_icon(
+ ':/images/textpointer.png', QColor(self._text_action.data())))
+ self.text_button_triggered()
+
+ @Slot()
+ def item_color_changed(self):
+ self._fill_action = self.sender()
+ self._fill_color_tool_button.setIcon(self.create_color_tool_button_icon(
+ ':/images/floodfill.png', QColor(self._fill_action.data())))
+ self.fill_button_triggered()
+
+ @Slot()
+ def line_color_changed(self):
+ self._line_action = self.sender()
+ self._line_color_tool_button.setIcon(self.create_color_tool_button_icon(
+ ':/images/linecolor.png', QColor(self._line_action.data())))
+ self.line_button_triggered()
+
+ @Slot()
+ def text_button_triggered(self):
+ self.scene.set_text_color(QColor(self._text_action.data()))
+
+ @Slot()
+ def fill_button_triggered(self):
+ self.scene.set_item_color(QColor(self._fill_action.data()))
+
+ @Slot()
+ def line_button_triggered(self):
+ self.scene.set_line_color(QColor(self._line_action.data()))
+
+ @Slot()
+ def handle_font_change(self):
+ font = self._font_combo.currentFont()
+ font.setPointSize(int(self._font_size_combo.currentText()))
+ if self._bold_action.isChecked():
+ font.setWeight(QFont.Bold)
else:
- font.setWeight(QtGui.QFont.Normal)
- font.setItalic(self.italicAction.isChecked())
- font.setUnderline(self.underlineAction.isChecked())
+ font.setWeight(QFont.Normal)
+ font.setItalic(self._italic_action.isChecked())
+ font.setUnderline(self._underline_action.isChecked())
- self.scene.setFont(font)
+ self.scene.set_font(font)
- def itemSelected(self, item):
+ @Slot(QGraphicsItem)
+ def item_selected(self, item):
font = item.font()
- color = item.defaultTextColor()
- self.fontCombo.setCurrentFont(font)
- self.fontSizeCombo.setEditText(str(font.pointSize()))
- self.boldAction.setChecked(font.weight() == QtGui.QFont.Bold)
- self.italicAction.setChecked(font.italic())
- self.underlineAction.setChecked(font.underline())
+ self._font_combo.setCurrentFont(font)
+ self._font_size_combo.setEditText(str(font.pointSize()))
+ self._bold_action.setChecked(font.weight() == QFont.Bold)
+ self._italic_action.setChecked(font.italic())
+ self._underline_action.setChecked(font.underline())
+ @Slot()
def about(self):
- QtWidgets.QMessageBox.about(self, "About Diagram Scene",
- "The <b>Diagram Scene</b> example shows use of the graphics framework.")
-
- def createToolBox(self):
- self.buttonGroup = QtWidgets.QButtonGroup()
- self.buttonGroup.setExclusive(False)
- self.buttonGroup.buttonClicked[int].connect(self.buttonGroupClicked)
-
- layout = QtWidgets.QGridLayout()
- layout.addWidget(self.createCellWidget("Conditional", DiagramItem.Conditional),
- 0, 0)
- layout.addWidget(self.createCellWidget("Process", DiagramItem.Step), 0,
- 1)
- layout.addWidget(self.createCellWidget("Input/Output", DiagramItem.Io),
- 1, 0)
-
- textButton = QtWidgets.QToolButton()
- textButton.setCheckable(True)
- self.buttonGroup.addButton(textButton, self.InsertTextButton)
- textButton.setIcon(QtGui.QIcon(QtGui.QPixmap(':/images/textpointer.png')
+ QMessageBox.about(self, "About Diagram Scene",
+ "The <b>Diagram Scene</b> example shows use of the graphics framework.")
+
+ def create_tool_box(self):
+ self._button_group = QButtonGroup()
+ self._button_group.setExclusive(False)
+ self._button_group.idClicked.connect(self.button_group_clicked)
+
+ layout = QGridLayout()
+ layout.addWidget(self.create_cell_widget("Conditional", DiagramItem.Conditional), 0, 0)
+ layout.addWidget(self.create_cell_widget("Process", DiagramItem.Step), 0, 1)
+ layout.addWidget(self.create_cell_widget("Input/Output", DiagramItem.Io), 1, 0)
+
+ text_button = QToolButton()
+ text_button.setCheckable(True)
+ self._button_group.addButton(text_button, self.insert_text_button)
+ text_button.setIcon(QIcon(QPixmap(':/images/textpointer.png')
.scaled(30, 30)))
- textButton.setIconSize(QtCore.QSize(50, 50))
+ text_button.setIconSize(QSize(50, 50))
- textLayout = QtWidgets.QGridLayout()
- textLayout.addWidget(textButton, 0, 0, QtCore.Qt.AlignHCenter)
- textLayout.addWidget(QtWidgets.QLabel("Text"), 1, 0,
- QtCore.Qt.AlignCenter)
- textWidget = QtWidgets.QWidget()
- textWidget.setLayout(textLayout)
- layout.addWidget(textWidget, 1, 1)
+ text_layout = QGridLayout()
+ text_layout.addWidget(text_button, 0, 0, Qt.AlignHCenter)
+ text_layout.addWidget(QLabel("Text"), 1, 0, Qt.AlignCenter)
+ text_widget = QWidget()
+ text_widget.setLayout(text_layout)
+ layout.addWidget(text_widget, 1, 1)
layout.setRowStretch(3, 10)
layout.setColumnStretch(2, 10)
- itemWidget = QtWidgets.QWidget()
- itemWidget.setLayout(layout)
-
- self.backgroundButtonGroup = QtWidgets.QButtonGroup()
- self.backgroundButtonGroup.buttonClicked.connect(self.backgroundButtonGroupClicked)
-
- backgroundLayout = QtWidgets.QGridLayout()
- backgroundLayout.addWidget(self.createBackgroundCellWidget("Blue Grid",
- ':/images/background1.png'), 0, 0)
- backgroundLayout.addWidget(self.createBackgroundCellWidget("White Grid",
- ':/images/background2.png'), 0, 1)
- backgroundLayout.addWidget(self.createBackgroundCellWidget("Gray Grid",
- ':/images/background3.png'), 1, 0)
- backgroundLayout.addWidget(self.createBackgroundCellWidget("No Grid",
- ':/images/background4.png'), 1, 1)
-
- backgroundLayout.setRowStretch(2, 10)
- backgroundLayout.setColumnStretch(2, 10)
-
- backgroundWidget = QtWidgets.QWidget()
- backgroundWidget.setLayout(backgroundLayout)
-
- self.toolBox = QtWidgets.QToolBox()
- self.toolBox.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Ignored))
- self.toolBox.setMinimumWidth(itemWidget.sizeHint().width())
- self.toolBox.addItem(itemWidget, "Basic Flowchart Shapes")
- self.toolBox.addItem(backgroundWidget, "Backgrounds")
-
- def createActions(self):
- self.toFrontAction = QtWidgets.QAction(
- QtGui.QIcon(':/images/bringtofront.png'), "Bring to &Front",
- self, shortcut="Ctrl+F", statusTip="Bring item to front",
- triggered=self.bringToFront)
-
- self.sendBackAction = QtWidgets.QAction(
- QtGui.QIcon(':/images/sendtoback.png'), "Send to &Back", self,
- shortcut="Ctrl+B", statusTip="Send item to back",
- triggered=self.sendToBack)
-
- self.deleteAction = QtWidgets.QAction(QtGui.QIcon(':/images/delete.png'),
- "&Delete", self, shortcut="Delete",
- statusTip="Delete item from diagram",
- triggered=self.deleteItem)
-
- self.exitAction = QtWidgets.QAction("E&xit", self, shortcut="Ctrl+X",
- statusTip="Quit Scenediagram example", triggered=self.close)
-
- self.boldAction = QtWidgets.QAction(QtGui.QIcon(':/images/bold.png'),
- "Bold", self, checkable=True, shortcut="Ctrl+B",
- triggered=self.handleFontChange)
-
- self.italicAction = QtWidgets.QAction(QtGui.QIcon(':/images/italic.png'),
- "Italic", self, checkable=True, shortcut="Ctrl+I",
- triggered=self.handleFontChange)
-
- self.underlineAction = QtWidgets.QAction(
- QtGui.QIcon(':/images/underline.png'), "Underline", self,
- checkable=True, shortcut="Ctrl+U",
- triggered=self.handleFontChange)
-
- self.aboutAction = QtWidgets.QAction("A&bout", self, shortcut="Ctrl+B",
- triggered=self.about)
-
- def createMenus(self):
- self.fileMenu = self.menuBar().addMenu("&File")
- self.fileMenu.addAction(self.exitAction)
-
- self.itemMenu = self.menuBar().addMenu("&Item")
- self.itemMenu.addAction(self.deleteAction)
- self.itemMenu.addSeparator()
- self.itemMenu.addAction(self.toFrontAction)
- self.itemMenu.addAction(self.sendBackAction)
-
- self.aboutMenu = self.menuBar().addMenu("&Help")
- self.aboutMenu.addAction(self.aboutAction)
-
- def createToolbars(self):
- self.editToolBar = self.addToolBar("Edit")
- self.editToolBar.addAction(self.deleteAction)
- self.editToolBar.addAction(self.toFrontAction)
- self.editToolBar.addAction(self.sendBackAction)
-
- self.fontCombo = QtWidgets.QFontComboBox()
- self.fontCombo.currentFontChanged.connect(self.currentFontChanged)
-
- self.fontSizeCombo = QtWidgets.QComboBox()
- self.fontSizeCombo.setEditable(True)
+ item_widget = QWidget()
+ item_widget.setLayout(layout)
+
+ self._background_button_group = QButtonGroup()
+ self._background_button_group.buttonClicked.connect(self.background_button_group_clicked)
+
+ background_layout = QGridLayout()
+ background_layout.addWidget(
+ self.create_background_cell_widget("Blue Grid", ':/images/background1.png'), 0, 0)
+ background_layout.addWidget(
+ self.create_background_cell_widget("White Grid", ':/images/background2.png'), 0, 1)
+ background_layout.addWidget(
+ self.create_background_cell_widget("Gray Grid", ':/images/background3.png'), 1, 0)
+ background_layout.addWidget(
+ self.create_background_cell_widget("No Grid", ':/images/background4.png'), 1, 1)
+
+ background_layout.setRowStretch(2, 10)
+ background_layout.setColumnStretch(2, 10)
+
+ background_widget = QWidget()
+ background_widget.setLayout(background_layout)
+
+ self._tool_box = QToolBox()
+ self._tool_box.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored))
+ self._tool_box.setMinimumWidth(item_widget.sizeHint().width())
+ self._tool_box.addItem(item_widget, "Basic Flowchart Shapes")
+ self._tool_box.addItem(background_widget, "Backgrounds")
+
+ def create_actions(self):
+ self._to_front_action = QAction(
+ QIcon(':/images/bringtofront.png'), "Bring to &Front",
+ self, shortcut="Ctrl+F", statusTip="Bring item to front",
+ triggered=self.bring_to_front)
+
+ self._send_back_action = QAction(
+ QIcon(':/images/sendtoback.png'), "Send to &Back", self,
+ shortcut="Ctrl+B", statusTip="Send item to back",
+ triggered=self.send_to_back)
+
+ self._delete_action = QAction(QIcon(':/images/delete.png'),
+ "&Delete", self, shortcut="Delete",
+ statusTip="Delete item from diagram",
+ triggered=self.delete_item)
+
+ self._exit_action = QAction("E&xit", self, shortcut="Ctrl+X",
+ statusTip="Quit Scenediagram example", triggered=self.close)
+
+ self._bold_action = QAction(QIcon(':/images/bold.png'),
+ "Bold", self, checkable=True, shortcut="Ctrl+B",
+ triggered=self.handle_font_change)
+
+ self._italic_action = QAction(QIcon(':/images/italic.png'),
+ "Italic", self, checkable=True, shortcut="Ctrl+I",
+ triggered=self.handle_font_change)
+
+ self._underline_action = QAction(
+ QIcon(':/images/underline.png'), "Underline", self,
+ checkable=True, shortcut="Ctrl+U",
+ triggered=self.handle_font_change)
+
+ self._about_action = QAction("A&bout", self, shortcut="Ctrl+B", triggered=self.about)
+
+ def create_menus(self):
+ self._file_menu = self.menuBar().addMenu("&File")
+ self._file_menu.addAction(self._exit_action)
+
+ self._item_menu = self.menuBar().addMenu("&Item")
+ self._item_menu.addAction(self._delete_action)
+ self._item_menu.addSeparator()
+ self._item_menu.addAction(self._to_front_action)
+ self._item_menu.addAction(self._send_back_action)
+
+ self._about_menu = self.menuBar().addMenu("&Help")
+ self._about_menu.addAction(self._about_action)
+
+ def create_toolbars(self):
+ self._edit_tool_bar = self.addToolBar("Edit")
+ self._edit_tool_bar.addAction(self._delete_action)
+ self._edit_tool_bar.addAction(self._to_front_action)
+ self._edit_tool_bar.addAction(self._send_back_action)
+
+ self._font_combo = QFontComboBox()
+ self._font_combo.currentFontChanged.connect(self.current_font_changed)
+
+ self._font_size_combo = QComboBox()
+ self._font_size_combo.setEditable(True)
for i in range(8, 30, 2):
- self.fontSizeCombo.addItem(str(i))
- validator = QtGui.QIntValidator(2, 64, self)
- self.fontSizeCombo.setValidator(validator)
- self.fontSizeCombo.currentIndexChanged.connect(self.fontSizeChanged)
-
- self.fontColorToolButton = QtWidgets.QToolButton()
- self.fontColorToolButton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
- self.fontColorToolButton.setMenu(
- self.createColorMenu(self.textColorChanged, QtCore.Qt.black))
- self.textAction = self.fontColorToolButton.menu().defaultAction()
- self.fontColorToolButton.setIcon(
- self.createColorToolButtonIcon(':/images/textpointer.png',
- QtCore.Qt.black))
- self.fontColorToolButton.setAutoFillBackground(True)
- self.fontColorToolButton.clicked.connect(self.textButtonTriggered)
-
- self.fillColorToolButton = QtWidgets.QToolButton()
- self.fillColorToolButton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
- self.fillColorToolButton.setMenu(
- self.createColorMenu(self.itemColorChanged, QtCore.Qt.white))
- self.fillAction = self.fillColorToolButton.menu().defaultAction()
- self.fillColorToolButton.setIcon(
- self.createColorToolButtonIcon(':/images/floodfill.png',
- QtCore.Qt.white))
- self.fillColorToolButton.clicked.connect(self.fillButtonTriggered)
-
- self.lineColorToolButton = QtWidgets.QToolButton()
- self.lineColorToolButton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
- self.lineColorToolButton.setMenu(
- self.createColorMenu(self.lineColorChanged, QtCore.Qt.black))
- self.lineAction = self.lineColorToolButton.menu().defaultAction()
- self.lineColorToolButton.setIcon(
- self.createColorToolButtonIcon(':/images/linecolor.png',
- QtCore.Qt.black))
- self.lineColorToolButton.clicked.connect(self.lineButtonTriggered)
-
- self.textToolBar = self.addToolBar("Font")
- self.textToolBar.addWidget(self.fontCombo)
- self.textToolBar.addWidget(self.fontSizeCombo)
- self.textToolBar.addAction(self.boldAction)
- self.textToolBar.addAction(self.italicAction)
- self.textToolBar.addAction(self.underlineAction)
-
- self.colorToolBar = self.addToolBar("Color")
- self.colorToolBar.addWidget(self.fontColorToolButton)
- self.colorToolBar.addWidget(self.fillColorToolButton)
- self.colorToolBar.addWidget(self.lineColorToolButton)
-
- pointerButton = QtWidgets.QToolButton()
- pointerButton.setCheckable(True)
- pointerButton.setChecked(True)
- pointerButton.setIcon(QtGui.QIcon(':/images/pointer.png'))
- linePointerButton = QtWidgets.QToolButton()
- linePointerButton.setCheckable(True)
- linePointerButton.setIcon(QtGui.QIcon(':/images/linepointer.png'))
-
- self.pointerTypeGroup = QtWidgets.QButtonGroup()
- self.pointerTypeGroup.addButton(pointerButton, DiagramScene.MoveItem)
- self.pointerTypeGroup.addButton(linePointerButton,
- DiagramScene.InsertLine)
- self.pointerTypeGroup.buttonClicked[int].connect(self.pointerGroupClicked)
-
- self.sceneScaleCombo = QtWidgets.QComboBox()
- self.sceneScaleCombo.addItems(["50%", "75%", "100%", "125%", "150%"])
- self.sceneScaleCombo.setCurrentIndex(2)
- self.sceneScaleCombo.currentIndexChanged[str].connect(self.sceneScaleChanged)
-
- self.pointerToolbar = self.addToolBar("Pointer type")
- self.pointerToolbar.addWidget(pointerButton)
- self.pointerToolbar.addWidget(linePointerButton)
- self.pointerToolbar.addWidget(self.sceneScaleCombo)
-
- def createBackgroundCellWidget(self, text, image):
- button = QtWidgets.QToolButton()
+ self._font_size_combo.addItem(str(i))
+ validator = QIntValidator(2, 64, self)
+ self._font_size_combo.setValidator(validator)
+ self._font_size_combo.currentIndexChanged.connect(self.font_size_changed)
+
+ self._font_color_tool_button = QToolButton()
+ self._font_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
+ self._font_color_tool_button.setMenu(
+ self.create_color_menu(self.text_color_changed, Qt.black))
+ self._text_action = self._font_color_tool_button.menu().defaultAction()
+ self._font_color_tool_button.setIcon(
+ self.create_color_tool_button_icon(':/images/textpointer.png', Qt.black))
+ self._font_color_tool_button.setAutoFillBackground(True)
+ self._font_color_tool_button.clicked.connect(self.text_button_triggered)
+
+ self._fill_color_tool_button = QToolButton()
+ self._fill_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
+ self._fill_color_tool_button.setMenu(
+ self.create_color_menu(self.item_color_changed, Qt.white))
+ self._fill_action = self._fill_color_tool_button.menu().defaultAction()
+ self._fill_color_tool_button.setIcon(
+ self.create_color_tool_button_icon(':/images/floodfill.png', Qt.white))
+ self._fill_color_tool_button.clicked.connect(self.fill_button_triggered)
+
+ self._line_color_tool_button = QToolButton()
+ self._line_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
+ self._line_color_tool_button.setMenu(
+ self.create_color_menu(self.line_color_changed, Qt.black))
+ self._line_action = self._line_color_tool_button.menu().defaultAction()
+ self._line_color_tool_button.setIcon(
+ self.create_color_tool_button_icon(':/images/linecolor.png', Qt.black))
+ self._line_color_tool_button.clicked.connect(self.line_button_triggered)
+
+ self._text_tool_bar = self.addToolBar("Font")
+ self._text_tool_bar.addWidget(self._font_combo)
+ self._text_tool_bar.addWidget(self._font_size_combo)
+ self._text_tool_bar.addAction(self._bold_action)
+ self._text_tool_bar.addAction(self._italic_action)
+ self._text_tool_bar.addAction(self._underline_action)
+
+ self._color_tool_bar = self.addToolBar("Color")
+ self._color_tool_bar.addWidget(self._font_color_tool_button)
+ self._color_tool_bar.addWidget(self._fill_color_tool_button)
+ self._color_tool_bar.addWidget(self._line_color_tool_button)
+
+ pointer_button = QToolButton()
+ pointer_button.setCheckable(True)
+ pointer_button.setChecked(True)
+ pointer_button.setIcon(QIcon(':/images/pointer.png'))
+ line_pointer_button = QToolButton()
+ line_pointer_button.setCheckable(True)
+ line_pointer_button.setIcon(QIcon(':/images/linepointer.png'))
+
+ self._pointer_type_group = QButtonGroup()
+ self._pointer_type_group.addButton(pointer_button, DiagramScene.MoveItem)
+ self._pointer_type_group.addButton(line_pointer_button, DiagramScene.InsertLine)
+ self._pointer_type_group.idClicked.connect(self.pointer_group_clicked)
+
+ self._scene_scale_combo = QComboBox()
+ self._scene_scale_combo.addItems(["50%", "75%", "100%", "125%", "150%"])
+ self._scene_scale_combo.setCurrentIndex(2)
+ self._scene_scale_combo.currentTextChanged.connect(self.scene_scale_changed)
+
+ self._pointer_toolbar = self.addToolBar("Pointer type")
+ self._pointer_toolbar.addWidget(pointer_button)
+ self._pointer_toolbar.addWidget(line_pointer_button)
+ self._pointer_toolbar.addWidget(self._scene_scale_combo)
+
+ def create_background_cell_widget(self, text, image):
+ button = QToolButton()
button.setText(text)
- button.setIcon(QtGui.QIcon(image))
- button.setIconSize(QtCore.QSize(50, 50))
+ button.setIcon(QIcon(image))
+ button.setIconSize(QSize(50, 50))
button.setCheckable(True)
- self.backgroundButtonGroup.addButton(button)
+ self._background_button_group.addButton(button)
- layout = QtWidgets.QGridLayout()
- layout.addWidget(button, 0, 0, QtCore.Qt.AlignHCenter)
- layout.addWidget(QtWidgets.QLabel(text), 1, 0, QtCore.Qt.AlignCenter)
+ layout = QGridLayout()
+ layout.addWidget(button, 0, 0, Qt.AlignHCenter)
+ layout.addWidget(QLabel(text), 1, 0, Qt.AlignCenter)
- widget = QtWidgets.QWidget()
+ widget = QWidget()
widget.setLayout(layout)
return widget
- def createCellWidget(self, text, diagramType):
- item = DiagramItem(diagramType, self.itemMenu)
- icon = QtGui.QIcon(item.image())
+ def create_cell_widget(self, text, diagram_type):
+ item = DiagramItem(diagram_type, self._item_menu)
+ icon = QIcon(item.image())
- button = QtWidgets.QToolButton()
+ button = QToolButton()
button.setIcon(icon)
- button.setIconSize(QtCore.QSize(50, 50))
+ button.setIconSize(QSize(50, 50))
button.setCheckable(True)
- self.buttonGroup.addButton(button, diagramType)
+ self._button_group.addButton(button, diagram_type)
- layout = QtWidgets.QGridLayout()
- layout.addWidget(button, 0, 0, QtCore.Qt.AlignHCenter)
- layout.addWidget(QtWidgets.QLabel(text), 1, 0, QtCore.Qt.AlignCenter)
+ layout = QGridLayout()
+ layout.addWidget(button, 0, 0, Qt.AlignHCenter)
+ layout.addWidget(QLabel(text), 1, 0, Qt.AlignCenter)
- widget = QtWidgets.QWidget()
+ widget = QWidget()
widget.setLayout(layout)
return widget
- def createColorMenu(self, slot, defaultColor):
- colors = [QtCore.Qt.black, QtCore.Qt.white, QtCore.Qt.red, QtCore.Qt.blue, QtCore.Qt.yellow]
+ def create_color_menu(self, slot, defaultColor):
+ colors = [Qt.black, Qt.white, Qt.red, Qt.blue, Qt.yellow]
names = ["black", "white", "red", "blue", "yellow"]
- colorMenu = QtWidgets.QMenu(self)
+ color_menu = QMenu(self)
for color, name in zip(colors, names):
- action = QtWidgets.QAction(self.createColorIcon(color), name, self,
- triggered=slot)
- action.setData(QtGui.QColor(color))
- colorMenu.addAction(action)
+ action = QAction(self.create_color_icon(color), name, self, triggered=slot)
+ action.setData(QColor(color))
+ color_menu.addAction(action)
if color == defaultColor:
- colorMenu.setDefaultAction(action)
- return colorMenu
+ color_menu.setDefaultAction(action)
+ return color_menu
- def createColorToolButtonIcon(self, imageFile, color):
- pixmap = QtGui.QPixmap(50, 80)
- pixmap.fill(QtCore.Qt.transparent)
- painter = QtGui.QPainter(pixmap)
- image = QtGui.QPixmap(imageFile)
- target = QtCore.QRect(0, 0, 50, 60)
- source = QtCore.QRect(0, 0, 42, 42)
- painter.fillRect(QtCore.QRect(0, 60, 50, 80), color)
- painter.drawPixmap(target, image, source)
- painter.end()
+ def create_color_tool_button_icon(self, imageFile, color):
+ pixmap = QPixmap(50, 80)
+ pixmap.fill(Qt.transparent)
- return QtGui.QIcon(pixmap)
+ with QPainter(pixmap) as painter:
+ image = QPixmap(imageFile)
+ target = QRect(0, 0, 50, 60)
+ source = QRect(0, 0, 42, 42)
+ painter.fillRect(QRect(0, 60, 50, 80), color)
+ painter.drawPixmap(target, image, source)
- def createColorIcon(self, color):
- pixmap = QtGui.QPixmap(20, 20)
- painter = QtGui.QPainter(pixmap)
- painter.setPen(QtCore.Qt.NoPen)
- painter.fillRect(QtCore.QRect(0, 0, 20, 20), color)
- painter.end()
+ return QIcon(pixmap)
- return QtGui.QIcon(pixmap)
+ def create_color_icon(self, color):
+ pixmap = QPixmap(20, 20)
+ with QPainter(pixmap) as painter:
+ painter.setPen(Qt.NoPen)
+ painter.fillRect(QRect(0, 0, 20, 20), color)
-if __name__ == '__main__':
+ return QIcon(pixmap)
- import sys
- app = QtWidgets.QApplication(sys.argv)
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
- mainWindow = MainWindow()
- mainWindow.setGeometry(100, 100, 800, 500)
- mainWindow.show()
+ main_window = MainWindow()
+ main_window.setGeometry(100, 100, 800, 500)
+ main_window.show()
- sys.exit(app.exec_())
+ sys.exit(app.exec())
diff --git a/examples/widgets/graphicsview/diagramscene/diagramscene.pyproject b/examples/widgets/graphicsview/diagramscene/diagramscene.pyproject
index 0acabdd78..79b8c8658 100644
--- a/examples/widgets/graphicsview/diagramscene/diagramscene.pyproject
+++ b/examples/widgets/graphicsview/diagramscene/diagramscene.pyproject
@@ -1,3 +1,3 @@
{
- "files": ["diagramscene.qrc", "diagramscene.py", "diagramscene_rc.py"]
+ "files": ["diagramscene.qrc", "diagramscene.py"]
}
diff --git a/examples/widgets/graphicsview/diagramscene/diagramscene_rc.py b/examples/widgets/graphicsview/diagramscene/diagramscene_rc.py
index 8fee5a0d6..144d9200f 100644
--- a/examples/widgets/graphicsview/diagramscene/diagramscene_rc.py
+++ b/examples/widgets/graphicsview/diagramscene/diagramscene_rc.py
@@ -1,149 +1,11 @@
# 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\x00\xf7\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x0b\x00\x00\x00\x0c\x08\x06\x00\x00\x00\xb4\xa9G\x9e\
-\x00\x00\x00\xbeIDAT(S\x85\x911\x0e@@\
-\x10EWM$J7\xa1\xa4\x918\x85^t\xaa=\
-\x8aNT{\x80\xadun\xa0\xd1l\xe7\x12\xc4\x97\x19\
-\xb1!YQ\xfcb\xfe\xbc\xfc\x99\xcc\x08\x00\x82t\x1c\
-\x07\xa6i\x82\x10\xc2)\xcf\xf3.\xf0\xd68\x8e\xa8\xaa\
-\x8aU\x14\x05\x03I\x92X\xef\x05?\xd5u\x1d\xc3Z\
-k\xd0T\xf2\x9c 5\xeb\xbafx]W\xdc\xfeg\
-r\x9a\xa6\x88\xe3\x18O\xcf\x09n\xdb\x06\xdf\xf7Q\x96\
-\xa5]\xc1\x09Ss\x9eg^AJ\xf9\x9f<\x0c\x03\
-\xc3J\xa9\xff\xe4\xb6m\x19^\x96\xe5?9\xcfs\x84\
-a\x88}\xdf\xdf\xc9T\x18c\xec\xe1IA\x10 \x8a\
-\x22[7M\x03\x9b\xdc\xf7\xfd\xf5\xce\x8fWgY\xc6\
-\x13N\xfaWVX\xe8@\xda\xc6\x00\x00\x00\x00IE\
-ND\xaeB`\x82\
-\x00\x00\x01\x1a\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00*\x00\x00\x00+\x02\x03\x00\x00\x00s\xf1\xf2m\
-\x00\x00\x00\x0cPLTE\xff\xff\xff\x80\x80\x80\x00\x00\
-\x00\xff\xff\xffEJK8\x00\x00\x00\x01tRNS\
-\x00@\xe6\xd8f\x00\x00\x00\xbcIDATx^M\
-\xcb\xbd\x89\x041\x0c\x86a\xa1\xd0U8\x1c\xdc\x8f&\
-\xd8\x12\xa6\x0a\xb3\xe1\xe6N.2\x07\x02\xdb\x07[\xc0\
-\x96\xb4U\x9cG?3V\xf4!\xde\x07B\xcd\xe0\x17\
-F\xbd\xf6\xb6\xec\x1a\xef\xa6A\x024\xb2A\x80`$\
-\xcf\x9d\x9a\xee8\x8b~x\x83O~d\xb30hW\
-\x102t\x22\x05\x98\x91\x89\x0c\xe4P\x88\x0c\xd4D\xe4\
- \xce\xdc\xc1\x98\x89\x833q \x89\x02\xe4\x9d\x1d`\
-\xa1.@\xff\xe9\x02\xfd\xf1*\x0e\xd2\xfe{\x81P\xda\
-\x02\x8e\xef\x02>\x0bx\xb3l\x01\x7f]\x1a\x03f\x1d\
-4\x00\x03B\x15\xb0\xe4\x0a$7P$W\xc0\x92+\
-\xe8\x92\x1b\x90\xdc\x80\xe4\x0a$7\xf0so\x1cp_\
-[v<\xc7?\xd6Qh R\x85\xdb_\x00\x00\x00\
-\x00IEND\xaeB`\x82\
-\x00\x00\x00\xfa\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x0b\x00\x00\x00\x0c\x08\x06\x00\x00\x00\xb4\xa9G\x9e\
-\x00\x00\x00\xc1IDAT(S\xcd\x901\x0a\x840\
-\x10E\xc7\xceV\xb0\xd3F\x10o`\xe5\x01\xbcB@\
-\x0b\x9bt\x22\x11\xbc\x94\x9d'\xd2\x03x\x03\x03\x19\xf7\
-\x0f\xb8\xd9,l\xbf\x81Of\xde\xfc|\xc8P\x1c\xc7\
-LD\xa2(\x8a8\xcfs~\x1d\xc2\xfd\xc9\xd34e\
-\xd2ZsQ\x14\x02\x86a\xe0y\x9e\xc5\x8c\x1b=8\
-\xe6\xe382a\xa0\x94\x12\x88\xfa[\xe0\x98;\xe7B\
-3\xc0/3\xea\x7fJ\xee\xbaN\xcc\xd7u\x05\x0f\xd0\
-\x83\xf7}\xef\x93\xb1&\xc0}\xdf\x03\xf3q\x1c\xc2\x97\
-e\xf1\xc9\xeb\xba\x0a\x9c\xa6)0?!\xdb\xb6\xf9d\
-\xa8\xaek\x19\x94e\xc9m\xdbrUU\xd27M\xc3\
-\xd6Z\x9f\xfc\xc8\x18\xc3Y\x96\x89)I\x12\xc6_\xce\
-\xf3|o\xe9\x063 8\xcd\x08\x1exv\x00\x00\x00\
-\x00IEND\xaeB`\x82\
-\x00\x00\x00r\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
-\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
-\xd3~\x00\x00\x00'IDATH\xc7c`\x80\x82\
-\x06\x0640*0*0*0*\x80*\xf0\x1f\x15\
-\xfc\x1b\x0d\xa0Q\x81Q\x81Q\x01\x22\x05\x00\xd5;N\
-\xf0s\xe3o\xe9\x00\x00\x00\x00IEND\xaeB`\
-\x82\
-\x00\x00\x02\xf1\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00*\x00\x00\x00,\x08\x03\x00\x00\x00$D\xdat\
-\x00\x00\x012PLTE\xff\xff\xff\xfe\xfe\xfe\x01\x01\
-\x01\xbe\xbe\xbe\xfd\xfd\xfd\x00\x00\x00ddd\xd2\xd2\xd2\
-|||\xfb\xfb\xfb\xe7\xe7\xe7\x84\x84\x84\xd7\xd7\xd7\xe0\
-\xe0\xe0\xe1\xe1\xe1\x0c\x0c\x0c(((\xf5\xf5\xf5\xb3\xb3\
-\xb3\x02\x02\x02\x95\x95\x95...\x11\x11\x11kkk\
-\x03\x03\x03rrrIII\xfc\xfc\xfc\x13\x13\x13\x04\
-\x04\x04\x9f\x9f\x9f\xc4\xc4\xc4\xa9\xa9\xa9\x05\x05\x05WW\
-W\x17\x17\x17\xf6\xf6\xf6\x16\x16\x16\xa6\xa6\xa6\xa0\xa0\xa0\
-```$$$>>>###\xb7\xb7\xb7M\
-MM\xf8\xf8\xf8\xc0\xc0\xc0000\x09\x09\x09\xec\xec\
-\xec \x8a\x8a\x8a\xda\xda\xda\xf1\xf1\xf1\x0d\x0d\x0d\
-\x99\x99\x99\x19\x19\x19\xf9\xf9\xf9\xcd\xcd\xcd\xf4\xf4\xf49\
-99---;;;\x12\x12\x12CCC\xc2\xc2\
-\xc2\xa4\xa4\xa4\xdc\xdc\xdcUUUhhhZZZ\
-PPP\xf0\xf0\xf0\x06\x06\x06\x1f\x1f\x1fttt\xb1\
-\xb1\xb1]]]!!!666\x08\x08\x08\xea\xea\
-\xea\xdb\xdb\xdb\x81\x81\x81\x9c\x9c\x9c\x8b\x8b\x8buuu\
-\xf2\xf2\xf2%%%\xce\xce\xceHHHccc\xba\
-\xba\xbaSSS888\xf7\xf7\xf7\xe4\xe4\xe4\xa2\xa2\
-\xa2JJJ\xf3\xf3\xf3___\xf1i\x00\xec\x00\x00\
-\x00\x01tRNS\x00@\xe6\xd8f\x00\x00\x01mI\
-DATx^\xd5\x92\xc5v\xc30\x10E=\x92\x1d\
-f\xe6\x94\x99\x99\x99\x99\x99\xe1\xff\x7f\xa1\x9e\x89\x93S\
-\xa9\xb2Nvm\xdf\xf2\xea\xfa\xbdY\xd8\xf8+\xf10\
-\xeb[X\xcc\x047\x13<\x96\x10\xc6\xb5\xadB\xda\x9a\
-om\x0d@\xb3\xad,\xe8\xda\x1a\xe2\xb5\xf4\xd4\xddq\
-\xbf\xa1\x0d\x14{\x1b\xed\x09\xd0\xbb\x03\x0d\x93\x0d\xeaM\
-\xd8A+3\x82n.\xac5\xc39\xbb\x95\xe5\xbb\xa9\
-\xdb\xa7\xbd\xc0G\xcedG'~1;\xa7q\x87\xda\
-\xd1,\x00\xf8\xe8\xda\x16\xcd~\x17\x19\x09\xc3\x88\x94\xd1\
-]\xd5\xb4\xf6\xe1n\xbf\xdf66\xe9\x92\x90\xab\xeb\xa5\
-\xf7\x09\xdb\x84a\xea\xcf\xbb\xeeg\xd1\x1c\x1dC`\xa6\
-\xd1]\x89\xbb\x98S\xd3\xb8\xef\xa9\x81\x19Z\xa8\x80\xda\
-M\xd1\xeb<\xbd\xc2B\x06\xbf[T\x9b\xe6\x12\x9a\xcb\
-N\x0f\x1c\xd0\xb5w\xca\xfd5z[\xaf\x83\x8d$\xba\
-[\xca\x0b\xb6q_\x0a\x8b\xee*\xdc\xc0\x9e\xa5\x08K\
-)\xf6\x83\x962i\xf3\x87\xe9\xdfgj\xb7\x0a\xb2{\
-\xe8b\xb2#\xd9\x84\x02\xf2c.\xe4\x04\xd9\xe9\x99d\
-\x9eS\xc3\x85H/i\xe9\x0aDzmS\x96\x8c\x08\
-\x14n\xa2Ho\x8b\x02\x8d\x97\xb0\xf5\x1e\xa4\xad\x07\xda\
-z\x14XE\xfd\xd7W\xe9\x82'\xa1\xe1\x19\x97J/\
-r\xab\x19C^~\xads\xce\xf9\x1b}\xfd\xce1\x1f\
-\xe0`\xcc'\xademL\xcc\x12\xc2\xbcN#\x139\
-A\x89y\xc1P5\xfc~\xeb\xff\xca\x17Uq \xbb\
-\xd7\xbb.\xca\x00\x00\x00\x00IEND\xaeB`\x82\
-\
-\x00\x00\x01>\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4l;\
-\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\
-\xa7\x93\x00\x00\x00\xf3IDAT8\xcb\xed\x94An\
-\x830\x10E\x9f%\xe0\x0c\xbdC/\xd0\x13\xe5\xfaU\
-b\x9b\xd83\x01w\x81\x0d$\x85\xaa1\xca\xaa\x1d\x89\
-\x8d\x0dO\xef{\x067m\xdb&\x0e\x94\xaa\x9a\xad\xf5\
-\x06@D\xaa\xa0]\xd7\xed\xee5\xbc\xa8\xfe\xc1\x7f\x01\
-l\x8c\xd9\xdbJ\x87\x8dS\xda`\x8c\x03\x0c\x01\xf4\x0a\
-\xd2Ct\x98\xb7\xf7\x83G1*h\x81z\x10\x07\xd1\
-\x1d<\xe3A&\xa0\xf6\x0b48\x88\x97Jp\x1aa\
-\x88Kt\xf5\x93e\xb4\xd3#5\xc6i\x80[\x00)\
-\xd1=\xa8\x83`W`_\x01\x96\x1c}\xb6|0\x95\
-jp\xfep\x06\xba\x15\xd4\xe5\x14v\x01\xfft\xfd\xdd\
-U\xb8\xe4\xce\xdb\x05\x5c&A\xfd\xb2\x064{\x17\xf5\
-\xe6\x8f\x10\xce\xdf\xa1\xc54\xe6\x89\xa8j^\xf8\x9cF\
-j\xb6t\x10\xb3\xa9\xac\x1a\xf84\xf8z\xce\xa6\x16b\
-\x0fj\xef\x1bXRT\x81\xa5\x98nLE\xf4p\xeb\
-\x9f\x07\x9b\x8f\xd3\xaf\xdf\xfd\x02\xd6\xbd\xde\xdfp\xdb\x04\
-\x83\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x00\xad\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@@ -157,56 +19,47 @@ r\x1f\x17a\x1aW\x9e\x80A\xb9\xf3\x82@\xeb\xc8B\
\xfed\xcc\x8f\xdc\x17\xd9\x83\xf6\x1e\xe4\xd8\xdd\xe3\xd8\x1d\
sa.\xb4\x8e'\xf0\x07\xd5\x18\x11\x1b\xedM#\xf4\
\x00\x00\x00\x00IEND\xaeB`\x82\
-\x00\x00\x00p\
+\x00\x00\x01\x12\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
-\x00\x00\x00\x06PLTE\x00\xff\xff\xff\xff\xff\xb1\xb8\
-^\xa0\x00\x00\x00%IDATx^\xed\xcc!\x12\
-\x00\x00\x04\x00A\xff\x7f4\x82\x11du/n\xb8\xd8\
-j\xca\x0b\x00\x00\xf0\x9d\x01\x00@\x03\x94\x98\xeb\xc0\x19\
-8\xa1\x84\x00\x00\x00\x00IEND\xaeB`\x82\
-\x00\x00\x00\x91\
+\x00\x00\x0b\x00\x00\x00\x0d\x08\x06\x00\x00\x00\x7f\xf5\x94;\
+\x00\x00\x00\xd9IDAT(S}\x901\x0eE@\
+\x10\x86G$$\x1a\x0d\x0d\xd1\x22Qp\x80m\x5c@\
+\xe7<\x0e!\x0aGq\x19\xb5N\xa9\xc1x3\xb2\x8b\
+\xf7\xec\xdb\xe4\xcbfv\xfe\xf9gv\xc00\x0c\x04\x80\
+\x07\xf4fY\x16&I\x82\x9f\x03\xc4\xbe\xef\x94;\x05\
+i\x9a2$\x08\xc3\xf0QX\xd75\x17\x01\x05\x04U\
+\xde]\xe8v\x1c\x87s\xb6m\xe3\xc3Y\x0a\xefDQ\
+\xc4\xe2 \x08\xf4\xce\xeb\xbab\xdb\xb6j\x94\xbe\xefO\
+\xb1|(\x8a\x82\xc9\xf3\x1c}\xdfg\x03!\x04\x0e\xc3\
+\xa0L@\xb7\x0d\xd34Y\xdcu\xdd%\xfe\x9ey\xdb\
+6\x9c\xa6\x89c\xd9!\x8ec\x1c\xc7\x11\xd5\xcco\x1f\
+$d\xbe\xaa\xaa\xff\xdbX\x96E\x8dF]^\xb7A\
+\xcc\xf3\x8cM\xd3\xa0\xccgYv9{\x9e\xa7p]\
+\xf7\xe7\xd3\xdamH\xa8\xa8,K\xd5\xf1\x00\xd0\xc0\x13\
+\xc8\x06\xaf\x16(\x00\x00\x00\x00IEND\xaeB`\
+\x82\
+\x00\x00\x00r\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00*\x00\x00\x00+\x01\x03\x00\x00\x004Q\x88\xbd\
+\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
-\xd3~\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\
-\x00\x009IDAT\x18Wc`\xc0\x05\x14 T\
-\x01\x84\xfa\x01&\x19\xff\x80)f\x08\x8f\xfd\x03\x98\xe2\
-\x7f\x00\xa6\xe4\x0f\x80)\xfb\x060U\x0f\xd1\xf6oP\
-k\xe3\x87hc\x83P,\x0c\x84\x00\x00\x91\xca\x1c\x09\
-\xf6#*\xfe\x00\x00\x00\x00IEND\xaeB`\x82\
-\
-\x00\x00\x01%\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4l;\
-\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\
-\xa7\x93\x00\x00\x00\xdaIDATH\xc7\xed\x94A\x0e\
-\x820\x10E\x1fF8\x83w\xf0\xfe\x87\xf0\x1a^@\
-\xb1\xa5t\xa6\x1a\x5c\xb4\x04\x8c\xa2\x11\xca\xc2\xc4I\xd8\
-\xd0\xe4\xe5\xf5\xf7g\x8a\xb2,;\x16L\x08\xa1x\xf5\
-\x7f\x0b\xa0\xaa\xb3\xa0UUM\x9emXi\xfe\xe0\x1f\
-\x06o30\xbaU\xc0\xdd\xed\x0a7\x0f\xa1\x05u \
-\x96b\xb7\xcf`\x1c\x5c\x826\xa0\x16\xc4f\x8aB\xed\
-\x00\xf5\x16\xe4\x92\x09,\x97h)&~\x9a\xcb\xd8\xd7\
-\xe0\xcd\x08\xdcd\x02\xbb\xf3`\xaa9\xc1\xed9A\xfb\
-\xac\xcd\x00~\xb7\xfe>g\x5c\xc7\x8cC\x93\xe2H\x19\
-O-\xeaW\x95\xed\x8e\x87!KI\x96\xbe\x8e\xa6\x92\
-\x1a1\xeb\xf1\xfc)V\xaa\xefk\xb0 \xc9TG\x0f\
-\xf85\xb8M\xd7V\x03\xe2 \x98\xc7\xaa\xf5\xb7\x98\x05\
-\xd6\xde\xd4>\xf7W\x1a\xb8:\x00\x8a\xa5\xcbfj\xee\
-\x91a\xa9f\xc0\x0f\xb5]\x00\x00\x00\x00IEND\
-\xaeB`\x82\
-\x00\x00\x00`\
+\xd3~\x00\x00\x00'IDATH\xc7c`\x80\x82\
+\x06\x0640*0*0*0*\x80*\xf0\x1f\x15\
+\xfc\x1b\x0d\xa0Q\x81Q\x81Q\x01\x22\x05\x00\xd5;N\
+\xf0s\xe3o\xe9\x00\x00\x00\x00IEND\xaeB`\
+\x82\
+\x00\x00\x00\x8d\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
-\x00\x00\x00\x03PLTE\xff\xff\xff\xa7\xc4\x1b\xc8\x00\
-\x00\x00\x18IDATx^\xed\xc01\x01\x00\x00\x00\
-\xc2 \xfb\xa76\xc5>X\x0b\x00\xe0\x08o\x00\x01\x01\
->\xc31\x00\x00\x00\x00IEND\xaeB`\x82\
+\x00\x00\x1b\x00\x00\x00\x1b\x01\x03\x00\x00\x00\xb7\x1af\x16\
+\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
+\xd3~\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\
+\x00\x005IDAT\x08\x99c`\xc0\x02\xd8\x1b\x80\
+\x04\xff\x01L\x82\xfd\x01H\xba\x00DX\x80\x08\x19\x10\
+\xc1\x07\xd6\x02\x22\x98A\xfa\x18A\x0a\x19\xc0\x0a\xeb@\
+\x84=\x16B\x0e\xddF\x00\xb5\x00\x09@\xa31\xbf^\
+\x00\x00\x00\x00IEND\xaeB`\x82\
\x00\x00\x03?\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@@ -261,37 +114,6 @@ I\x22\x8f\x8f\xc15\xf7\xdd\x12\xae\xb4\xf4\x04n\xa9\x0c\
\x8a\x88\xa6Y\xd6\xa8Syku\x9eO>\x8e\x1b\xec\
\x0f\xe4\x1a\xda\xa0h\xebM\xed\x7f=\xa9\x97\x96\x02\xf1\
+\x1c\x00\x00\x00\x00IEND\xaeB`\x82\
-\x00\x00\x00\x8d\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x1b\x00\x00\x00\x1b\x01\x03\x00\x00\x00\xb7\x1af\x16\
-\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
-\xd3~\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\
-\x00\x005IDAT\x08\x99c`\xc0\x02\xd8\x1b\x80\
-\x04\xff\x01L\x82\xfd\x01H\xba\x00DX\x80\x08\x19\x10\
-\xc1\x07\xd6\x02\x22\x98A\xfa\x18A\x0a\x19\xc0\x0a\xeb@\
-\x84=\x16B\x0e\xddF\x00\xb5\x00\x09@\xa31\xbf^\
-\x00\x00\x00\x00IEND\xaeB`\x82\
-\x00\x00\x01\x12\
-\x89\
-PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
-\x00\x00\x0b\x00\x00\x00\x0d\x08\x06\x00\x00\x00\x7f\xf5\x94;\
-\x00\x00\x00\xd9IDAT(S}\x901\x0eE@\
-\x10\x86G$$\x1a\x0d\x0d\xd1\x22Qp\x80m\x5c@\
-\xe7<\x0e!\x0aGq\x19\xb5N\xa9\xc1x3\xb2\x8b\
-\xf7\xec\xdb\xe4\xcbfv\xfe\xf9gv\xc00\x0c\x04\x80\
-\x07\xf4fY\x16&I\x82\x9f\x03\xc4\xbe\xef\x94;\x05\
-i\x9a2$\x08\xc3\xf0QX\xd75\x17\x01\x05\x04U\
-\xde]\xe8v\x1c\x87s\xb6m\xe3\xc3Y\x0a\xefDQ\
-\xc4\xe2 \x08\xf4\xce\xeb\xbab\xdb\xb6j\x94\xbe\xefO\
-\xb1|(\x8a\x82\xc9\xf3\x1c}\xdfg\x03!\x04\x0e\xc3\
-\xa0L@\xb7\x0d\xd34Y\xdcu\xdd%\xfe\x9ey\xdb\
-6\x9c\xa6\x89c\xd9!\x8ec\x1c\xc7\x11\xd5\xcco\x1f\
-$d\xbe\xaa\xaa\xff\xdbX\x96E\x8dF]^\xb7A\
-\xcc\xf3\x8cM\xd3\xa0\xccgYv9{\x9e\xa7p]\
-\xf7\xe7\xd3\xdamH\xa8\xa8,K\xd5\xf1\x00\xd0\xc0\x13\
-\xc8\x06\xaf\x16(\x00\x00\x00\x00IEND\xaeB`\
-\x82\
\x00\x00\x00t\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@@ -302,6 +124,184 @@ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
C\xc4\xff\x8d\x0a\x8c\x0a\x8c\x0a\x8c\x0a`\x17\x00\x00?\
x\xe4\xb7\xe3\x900_\x00\x00\x00\x00IEND\xae\
B`\x82\
+\x00\x00\x00`\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
+\x00\x00\x00\x03PLTE\xff\xff\xff\xa7\xc4\x1b\xc8\x00\
+\x00\x00\x18IDATx^\xed\xc01\x01\x00\x00\x00\
+\xc2 \xfb\xa76\xc5>X\x0b\x00\xe0\x08o\x00\x01\x01\
+>\xc31\x00\x00\x00\x00IEND\xaeB`\x82\
+\x00\x00\x00p\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x7f\x00\x00\x00\x7f\x01\x03\x00\x00\x00\xfcs\x8fP\
+\x00\x00\x00\x06PLTE\x00\xff\xff\xff\xff\xff\xb1\xb8\
+^\xa0\x00\x00\x00%IDATx^\xed\xcc!\x12\
+\x00\x00\x04\x00A\xff\x7f4\x82\x11du/n\xb8\xd8\
+j\xca\x0b\x00\x00\xf0\x9d\x01\x00@\x03\x94\x98\xeb\xc0\x19\
+8\xa1\x84\x00\x00\x00\x00IEND\xaeB`\x82\
+\x00\x00\x01>\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4l;\
+\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\
+\xa7\x93\x00\x00\x00\xf3IDAT8\xcb\xed\x94An\
+\x830\x10E\x9f%\xe0\x0c\xbdC/\xd0\x13\xe5\xfaU\
+b\x9b\xd83\x01w\x81\x0d$\x85\xaa1\xca\xaa\x1d\x89\
+\x8d\x0dO\xef{\x067m\xdb&\x0e\x94\xaa\x9a\xad\xf5\
+\x06@D\xaa\xa0]\xd7\xed\xee5\xbc\xa8\xfe\xc1\x7f\x01\
+l\x8c\xd9\xdbJ\x87\x8dS\xda`\x8c\x03\x0c\x01\xf4\x0a\
+\xd2Ct\x98\xb7\xf7\x83G1*h\x81z\x10\x07\xd1\
+\x1d<\xe3A&\xa0\xf6\x0b48\x88\x97Jp\x1aa\
+\x88Kt\xf5\x93e\xb4\xd3#5\xc6i\x80[\x00)\
+\xd1=\xa8\x83`W`_\x01\x96\x1c}\xb6|0\x95\
+jp\xfep\x06\xba\x15\xd4\xe5\x14v\x01\xfft\xfd\xdd\
+U\xb8\xe4\xce\xdb\x05\x5c&A\xfd\xb2\x064{\x17\xf5\
+\xe6\x8f\x10\xce\xdf\xa1\xc54\xe6\x89\xa8j^\xf8\x9cF\
+j\xb6t\x10\xb3\xa9\xac\x1a\xf84\xf8z\xce\xa6\x16b\
+\x0fj\xef\x1bXRT\x81\xa5\x98nLE\xf4p\xeb\
+\x9f\x07\x9b\x8f\xd3\xaf\xdf\xfd\x02\xd6\xbd\xde\xdfp\xdb\x04\
+\x83\x00\x00\x00\x00IEND\xaeB`\x82\
+\x00\x00\x00\xfa\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x0b\x00\x00\x00\x0c\x08\x06\x00\x00\x00\xb4\xa9G\x9e\
+\x00\x00\x00\xc1IDAT(S\xcd\x901\x0a\x840\
+\x10E\xc7\xceV\xb0\xd3F\x10o`\xe5\x01\xbcB@\
+\x0b\x9bt\x22\x11\xbc\x94\x9d'\xd2\x03x\x03\x03\x19\xf7\
+\x0f\xb8\xd9,l\xbf\x81Of\xde\xfc|\xc8P\x1c\xc7\
+LD\xa2(\x8a8\xcfs~\x1d\xc2\xfd\xc9\xd34e\
+\xd2ZsQ\x14\x02\x86a\xe0y\x9e\xc5\x8c\x1b=8\
+\xe6\xe382a\xa0\x94\x12\x88\xfa[\xe0\x98;\xe7B\
+3\xc0/3\xea\x7fJ\xee\xbaN\xcc\xd7u\x05\x0f\xd0\
+\x83\xf7}\xef\x93\xb1&\xc0}\xdf\x03\xf3q\x1c\xc2\x97\
+e\xf1\xc9\xeb\xba\x0a\x9c\xa6)0?!\xdb\xb6\xf9d\
+\xa8\xaek\x19\x94e\xc9m\xdbrUU\xd27M\xc3\
+\xd6Z\x9f\xfc\xc8\x18\xc3Y\x96\x89)I\x12\xc6_\xce\
+\xf3|o\xe9\x063 8\xcd\x08\x1exv\x00\x00\x00\
+\x00IEND\xaeB`\x82\
+\x00\x00\x01%\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4l;\
+\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\
+\xa7\x93\x00\x00\x00\xdaIDATH\xc7\xed\x94A\x0e\
+\x820\x10E\x1fF8\x83w\xf0\xfe\x87\xf0\x1a^@\
+\xb1\xa5t\xa6\x1a\x5c\xb4\x04\x8c\xa2\x11\xca\xc2\xc4I\xd8\
+\xd0\xe4\xe5\xf5\xf7g\x8a\xb2,;\x16L\x08\xa1x\xf5\
+\x7f\x0b\xa0\xaa\xb3\xa0UUM\x9emXi\xfe\xe0\x1f\
+\x06o30\xbaU\xc0\xdd\xed\x0a7\x0f\xa1\x05u \
+\x96b\xb7\xcf`\x1c\x5c\x826\xa0\x16\xc4f\x8aB\xed\
+\x00\xf5\x16\xe4\x92\x09,\x97h)&~\x9a\xcb\xd8\xd7\
+\xe0\xcd\x08\xdcd\x02\xbb\xf3`\xaa9\xc1\xed9A\xfb\
+\xac\xcd\x00~\xb7\xfe>g\x5c\xc7\x8cC\x93\xe2H\x19\
+O-\xeaW\x95\xed\x8e\x87!KI\x96\xbe\x8e\xa6\x92\
+\x1a1\xeb\xf1\xfc)V\xaa\xefk\xb0 \xc9TG\x0f\
+\xf85\xb8M\xd7V\x03\xe2 \x98\xc7\xaa\xf5\xb7\x98\x05\
+\xd6\xde\xd4>\xf7W\x1a\xb8:\x00\x8a\xa5\xcbfj\xee\
+\x91a\xa9f\xc0\x0f\xb5]\x00\x00\x00\x00IEND\
+\xaeB`\x82\
+\x00\x00\x00\x91\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00*\x00\x00\x00+\x01\x03\x00\x00\x004Q\x88\xbd\
+\x00\x00\x00\x06PLTE\xff\xff\xff\x00\x00\x00U\xc2\
+\xd3~\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\
+\x00\x009IDAT\x18Wc`\xc0\x05\x14 T\
+\x01\x84\xfa\x01&\x19\xff\x80)f\x08\x8f\xfd\x03\x98\xe2\
+\x7f\x00\xa6\xe4\x0f\x80)\xfb\x060U\x0f\xd1\xf6oP\
+k\xe3\x87hc\x83P,\x0c\x84\x00\x00\x91\xca\x1c\x09\
+\xf6#*\xfe\x00\x00\x00\x00IEND\xaeB`\x82\
+\
+\x00\x00\x02\xf1\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00*\x00\x00\x00,\x08\x03\x00\x00\x00$D\xdat\
+\x00\x00\x012PLTE\xff\xff\xff\xfe\xfe\xfe\x01\x01\
+\x01\xbe\xbe\xbe\xfd\xfd\xfd\x00\x00\x00ddd\xd2\xd2\xd2\
+|||\xfb\xfb\xfb\xe7\xe7\xe7\x84\x84\x84\xd7\xd7\xd7\xe0\
+\xe0\xe0\xe1\xe1\xe1\x0c\x0c\x0c(((\xf5\xf5\xf5\xb3\xb3\
+\xb3\x02\x02\x02\x95\x95\x95...\x11\x11\x11kkk\
+\x03\x03\x03rrrIII\xfc\xfc\xfc\x13\x13\x13\x04\
+\x04\x04\x9f\x9f\x9f\xc4\xc4\xc4\xa9\xa9\xa9\x05\x05\x05WW\
+W\x17\x17\x17\xf6\xf6\xf6\x16\x16\x16\xa6\xa6\xa6\xa0\xa0\xa0\
+```$$$>>>###\xb7\xb7\xb7M\
+MM\xf8\xf8\xf8\xc0\xc0\xc0000\x09\x09\x09\xec\xec\
+\xec \x8a\x8a\x8a\xda\xda\xda\xf1\xf1\xf1\x0d\x0d\x0d\
+\x99\x99\x99\x19\x19\x19\xf9\xf9\xf9\xcd\xcd\xcd\xf4\xf4\xf49\
+99---;;;\x12\x12\x12CCC\xc2\xc2\
+\xc2\xa4\xa4\xa4\xdc\xdc\xdcUUUhhhZZZ\
+PPP\xf0\xf0\xf0\x06\x06\x06\x1f\x1f\x1fttt\xb1\
+\xb1\xb1]]]!!!666\x08\x08\x08\xea\xea\
+\xea\xdb\xdb\xdb\x81\x81\x81\x9c\x9c\x9c\x8b\x8b\x8buuu\
+\xf2\xf2\xf2%%%\xce\xce\xceHHHccc\xba\
+\xba\xbaSSS888\xf7\xf7\xf7\xe4\xe4\xe4\xa2\xa2\
+\xa2JJJ\xf3\xf3\xf3___\xf1i\x00\xec\x00\x00\
+\x00\x01tRNS\x00@\xe6\xd8f\x00\x00\x01mI\
+DATx^\xd5\x92\xc5v\xc30\x10E=\x92\x1d\
+f\xe6\x94\x99\x99\x99\x99\x99\xe1\xff\x7f\xa1\x9e\x89\x93S\
+\xa9\xb2Nvm\xdf\xf2\xea\xfa\xbdY\xd8\xf8+\xf10\
+\xeb[X\xcc\x047\x13<\x96\x10\xc6\xb5\xadB\xda\x9a\
+om\x0d@\xb3\xad,\xe8\xda\x1a\xe2\xb5\xf4\xd4\xddq\
+\xbf\xa1\x0d\x14{\x1b\xed\x09\xd0\xbb\x03\x0d\x93\x0d\xeaM\
+\xd8A+3\x82n.\xac5\xc39\xbb\x95\xe5\xbb\xa9\
+\xdb\xa7\xbd\xc0G\xcedG'~1;\xa7q\x87\xda\
+\xd1,\x00\xf8\xe8\xda\x16\xcd~\x17\x19\x09\xc3\x88\x94\xd1\
+]\xd5\xb4\xf6\xe1n\xbf\xdf66\xe9\x92\x90\xab\xeb\xa5\
+\xf7\x09\xdb\x84a\xea\xcf\xbb\xeeg\xd1\x1c\x1dC`\xa6\
+\xd1]\x89\xbb\x98S\xd3\xb8\xef\xa9\x81\x19Z\xa8\x80\xda\
+M\xd1\xeb<\xbd\xc2B\x06\xbf[T\x9b\xe6\x12\x9a\xcb\
+N\x0f\x1c\xd0\xb5w\xca\xfd5z[\xaf\x83\x8d$\xba\
+[\xca\x0b\xb6q_\x0a\x8b\xee*\xdc\xc0\x9e\xa5\x08K\
+)\xf6\x83\x962i\xf3\x87\xe9\xdfgj\xb7\x0a\xb2{\
+\xe8b\xb2#\xd9\x84\x02\xf2c.\xe4\x04\xd9\xe9\x99d\
+\x9eS\xc3\x85H/i\xe9\x0aDzmS\x96\x8c\x08\
+\x14n\xa2Ho\x8b\x02\x8d\x97\xb0\xf5\x1e\xa4\xad\x07\xda\
+z\x14XE\xfd\xd7W\xe9\x82'\xa1\xe1\x19\x97J/\
+r\xab\x19C^~\xads\xce\xf9\x1b}\xfd\xce1\x1f\
+\xe0`\xcc'\xademL\xcc\x12\xc2\xbcN#\x139\
+A\x89y\xc1P5\xfc~\xeb\xff\xca\x17Uq \xbb\
+\xd7\xbb.\xca\x00\x00\x00\x00IEND\xaeB`\x82\
+\
+\x00\x00\x01\x1a\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00*\x00\x00\x00+\x02\x03\x00\x00\x00s\xf1\xf2m\
+\x00\x00\x00\x0cPLTE\xff\xff\xff\x80\x80\x80\x00\x00\
+\x00\xff\xff\xffEJK8\x00\x00\x00\x01tRNS\
+\x00@\xe6\xd8f\x00\x00\x00\xbcIDATx^M\
+\xcb\xbd\x89\x041\x0c\x86a\xa1\xd0U8\x1c\xdc\x8f&\
+\xd8\x12\xa6\x0a\xb3\xe1\xe6N.2\x07\x02\xdb\x07[\xc0\
+\x96\xb4U\x9cG?3V\xf4!\xde\x07B\xcd\xe0\x17\
+F\xbd\xf6\xb6\xec\x1a\xef\xa6A\x024\xb2A\x80`$\
+\xcf\x9d\x9a\xee8\x8b~x\x83O~d\xb30hW\
+\x102t\x22\x05\x98\x91\x89\x0c\xe4P\x88\x0c\xd4D\xe4\
+ \xce\xdc\xc1\x98\x89\x833q \x89\x02\xe4\x9d\x1d`\
+\xa1.@\xff\xe9\x02\xfd\xf1*\x0e\xd2\xfe{\x81P\xda\
+\x02\x8e\xef\x02>\x0bx\xb3l\x01\x7f]\x1a\x03f\x1d\
+4\x00\x03B\x15\xb0\xe4\x0a$7P$W\xc0\x92+\
+\xe8\x92\x1b\x90\xdc\x80\xe4\x0a$7\xf0so\x1cp_\
+[v<\xc7?\xd6Qh R\x85\xdb_\x00\x00\x00\
+\x00IEND\xaeB`\x82\
+\x00\x00\x00\xf7\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x0b\x00\x00\x00\x0c\x08\x06\x00\x00\x00\xb4\xa9G\x9e\
+\x00\x00\x00\xbeIDAT(S\x85\x911\x0e@@\
+\x10EWM$J7\xa1\xa4\x918\x85^t\xaa=\
+\x8aNT{\x80\xadun\xa0\xd1l\xe7\x12\xc4\x97\x19\
+\xb1!YQ\xfcb\xfe\xbc\xfc\x99\xcc\x08\x00\x82t\x1c\
+\x07\xa6i\x82\x10\xc2)\xcf\xf3.\xf0\xd68\x8e\xa8\xaa\
+\x8aU\x14\x05\x03I\x92X\xef\x05?\xd5u\x1d\xc3Z\
+k\xd0T\xf2\x9c 5\xeb\xbafx]W\xdc\xfeg\
+r\x9a\xa6\x88\xe3\x18O\xcf\x09n\xdb\x06\xdf\xf7Q\x96\
+\xa5]\xc1\x09Ss\x9eg^AJ\xf9\x9f<\x0c\x03\
+\xc3J\xa9\xff\xe4\xb6m\x19^\x96\xe5?9\xcfs\x84\
+a\x88}\xdf\xdf\xc9T\x18c\xec\xe1IA\x10 \x8a\
+\x22[7M\x03\x9b\xdc\xf7\xfd\xf5\xce\x8fWgY\xc6\
+\x13N\xfaWVX\xe8@\xda\xc6\x00\x00\x00\x00IE\
+ND\xaeB`\x82\
"
qt_resource_name = b"\
@@ -309,66 +309,66 @@ qt_resource_name = b"\
\x07\x03}\xc3\
\x00i\
\x00m\x00a\x00g\x00e\x00s\
-\x00\x0a\
-\x02\xfcBG\
-\x00i\
-\x00t\x00a\x00l\x00i\x00c\x00.\x00p\x00n\x00g\
-\x00\x0d\
-\x06C\xe3g\
-\x00f\
-\x00l\x00o\x00o\x00d\x00f\x00i\x00l\x00l\x00.\x00p\x00n\x00g\
-\x00\x0d\
-\x08\xd5\xc4\xe7\
-\x00u\
-\x00n\x00d\x00e\x00r\x00l\x00i\x00n\x00e\x00.\x00p\x00n\x00g\
+\x00\x0b\
+\x0a+\x97\xe7\
+\x00p\
+\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
+\x00\x08\
+\x06'Zg\
+\x00b\
+\x00o\x00l\x00d\x00.\x00p\x00n\x00g\
\x00\x0f\
\x00I\xdb\xa7\
\x00b\
\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x002\x00.\x00p\x00n\x00g\
\x00\x0f\
-\x05\xaa\x0c\xc7\
-\x00t\
-\x00e\x00x\x00t\x00p\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
-\x00\x0e\
-\x0f\x0d\x22'\
-\x00s\
-\x00e\x00n\x00d\x00t\x00o\x00b\x00a\x00c\x00k\x00.\x00p\x00n\x00g\
-\x00\x0b\
-\x0a+\x97\xe7\
-\x00p\
-\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
+\x03J#\xe7\
+\x00l\
+\x00i\x00n\x00e\x00p\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
+\x00\x0a\
+\x0c\xad\x0f\x07\
+\x00d\
+\x00e\x00l\x00e\x00t\x00e\x00.\x00p\x00n\x00g\
+\x00\x0f\
+\x00J\xdb\xa7\
+\x00b\
+\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x003\x00.\x00p\x00n\x00g\
+\x00\x0f\
+\x00K\xdb\xa7\
+\x00b\
+\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x004\x00.\x00p\x00n\x00g\
\x00\x0f\
\x00P\xdb\xa7\
\x00b\
\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x001\x00.\x00p\x00n\x00g\
+\x00\x0e\
+\x0f\x0d\x22'\
+\x00s\
+\x00e\x00n\x00d\x00t\x00o\x00b\x00a\x00c\x00k\x00.\x00p\x00n\x00g\
\x00\x0d\
-\x05l\x22\xc7\
-\x00l\
-\x00i\x00n\x00e\x00c\x00o\x00l\x00o\x00r\x00.\x00p\x00n\x00g\
+\x08\xd5\xc4\xe7\
+\x00u\
+\x00n\x00d\x00e\x00r\x00l\x00i\x00n\x00e\x00.\x00p\x00n\x00g\
\x00\x10\
\x0f\x9b\x88g\
\x00b\
\x00r\x00i\x00n\x00g\x00t\x00o\x00f\x00r\x00o\x00n\x00t\x00.\x00p\x00n\x00g\
-\x00\x0f\
-\x00K\xdb\xa7\
-\x00b\
-\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x004\x00.\x00p\x00n\x00g\
-\x00\x0a\
-\x0c\xad\x0f\x07\
-\x00d\
-\x00e\x00l\x00e\x00t\x00e\x00.\x00p\x00n\x00g\
-\x00\x0f\
-\x03J#\xe7\
+\x00\x0d\
+\x05l\x22\xc7\
\x00l\
-\x00i\x00n\x00e\x00p\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
-\x00\x08\
-\x06'Zg\
-\x00b\
-\x00o\x00l\x00d\x00.\x00p\x00n\x00g\
+\x00i\x00n\x00e\x00c\x00o\x00l\x00o\x00r\x00.\x00p\x00n\x00g\
\x00\x0f\
-\x00J\xdb\xa7\
-\x00b\
-\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x003\x00.\x00p\x00n\x00g\
+\x05\xaa\x0c\xc7\
+\x00t\
+\x00e\x00x\x00t\x00p\x00o\x00i\x00n\x00t\x00e\x00r\x00.\x00p\x00n\x00g\
+\x00\x0d\
+\x06C\xe3g\
+\x00f\
+\x00l\x00o\x00o\x00d\x00f\x00i\x00l\x00l\x00.\x00p\x00n\x00g\
+\x00\x0a\
+\x02\xfcBG\
+\x00i\
+\x00t\x00a\x00l\x00i\x00c\x00.\x00p\x00n\x00g\
"
qt_resource_struct = b"\
@@ -376,36 +376,36 @@ qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x0f\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00l\x00\x00\x00\x00\x00\x01\x00\x00\x03\x17\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x01\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x0f\xf5\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x01\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xa7\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x00\xf2\x00\x00\x00\x00\x00\x01\x00\x00\x08u\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
+\x00\x00\x00D\x00\x00\x00\x00\x00\x01\x00\x00\x01\xc7\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x00\xa6\x00\x00\x00\x00\x00\x01\x00\x00\x06\x11\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x00\xca\x00\x00\x00\x00\x00\x01\x00\x00\x06\x89\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x00\xee\x00\x00\x00\x00\x00\x01\x00\x00\x06\xed\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x01\xde\x00\x00\x00\x00\x00\x01\x00\x00\x0fr\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x00h\x00\x00\x00\x00\x00\x01\x00\x00\x02=\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x01z\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xca\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x0b_\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x00.\x00\x00\x00\x00\x00\x01\x00\x00\x00\xb1\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x0eT\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x014\x00\x00\x00\x00\x00\x01\x00\x00\x08\xa3\
+\x00\x00\x01z\xe7\xee'\x09\
\x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x0eN\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x01\x16\x00\x00\x00\x00\x00\x01\x00\x00\x08\xe9\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x03\x8d\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xdf\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x00,\x00\x00\x00\x00\x00\x01\x00\x00\x00\xfb\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x00L\x00\x00\x00\x00\x00\x01\x00\x00\x02\x19\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x00\xd6\x00\x00\x00\x00\x00\x01\x00\x00\x07\xc4\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x01\x80\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x0b\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x00\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x06\x82\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
-\x00\x00\x016\x00\x00\x00\x00\x00\x01\x00\x00\x09~\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x02\xce\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x01\x12\x00\x00\x00\x00\x00\x01\x00\x00\x07a\
+\x00\x00\x01z\xe7\xee'\x09\
+\x00\x00\x01T\x00\x00\x00\x00\x00\x01\x00\x00\x09\xa1\
+\x00\x00\x01z\xe7\xee'\x09\
"
def qInitResources():
diff --git a/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.py b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.py
index 68a54d552..9ed92b26e 100644
--- a/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.py
+++ b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.py
@@ -1,188 +1,160 @@
+# 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$
-##
-#############################################################################
-
-from PySide2 import QtCore, QtGui, QtWidgets
-
-import dragdroprobot_rc
-
-
-class ColorItem(QtWidgets.QGraphicsItem):
+import sys
+import math
+
+from PySide6.QtCore import (QEasingCurve, QLineF, QMimeData, QPoint, QPointF,
+ QRandomGenerator, QRectF, QTimeLine, Qt)
+from PySide6.QtGui import (QBrush, QColor, QDrag, QImage, QPainter, QPixmap,
+ QPen, QTransform)
+from PySide6.QtWidgets import (QApplication, QGraphicsItem,
+ QGraphicsItemAnimation, QGraphicsScene,
+ QGraphicsView)
+
+import dragdroprobot_rc # noqa: F401
+
+
+def random(boundary):
+ return QRandomGenerator.global_().bounded(boundary)
+
+
+class ColorItem(QGraphicsItem):
n = 0
def __init__(self):
- super(ColorItem, self).__init__()
+ super().__init__()
- self.color = QtGui.QColor(QtCore.qrand() % 256, QtCore.qrand() % 256,
- QtCore.qrand() % 256)
+ self.color = QColor(random(256), random(256), random(256))
+ (r, g, b) = (self.color.red(), self.color.green(), self.color.blue())
self.setToolTip(
- "QColor(%d, %d, %d)\nClick and drag this color onto the robot!" %
- (self.color.red(), self.color.green(), self.color.blue())
- )
- self.setCursor(QtCore.Qt.OpenHandCursor)
+ f"QColor({r}, {g}, {b})\nClick and drag this color onto the robot!")
+ self.setCursor(Qt.OpenHandCursor)
+ self._start_drag_distance = QApplication.startDragDistance()
def boundingRect(self):
- return QtCore.QRectF(-15.5, -15.5, 34, 34)
+ return QRectF(-15.5, -15.5, 34, 34)
def paint(self, painter, option, widget):
- painter.setPen(QtCore.Qt.NoPen)
- painter.setBrush(QtCore.Qt.darkGray)
+ painter.setPen(Qt.NoPen)
+ painter.setBrush(Qt.darkGray)
painter.drawEllipse(-12, -12, 30, 30)
- painter.setPen(QtGui.QPen(QtCore.Qt.black, 1))
- painter.setBrush(QtGui.QBrush(self.color))
+ painter.setPen(QPen(Qt.black, 1))
+ painter.setBrush(QBrush(self.color))
painter.drawEllipse(-15, -15, 30, 30)
def mousePressEvent(self, event):
- if event.button() != QtCore.Qt.LeftButton:
+ if event.button() != Qt.LeftButton:
event.ignore()
return
- self.setCursor(QtCore.Qt.ClosedHandCursor)
+ self.setCursor(Qt.ClosedHandCursor)
def mouseMoveEvent(self, event):
- if QtCore.QLineF(QtCore.QPointF(event.screenPos()), QtCore.QPointF(event.buttonDownScreenPos(QtCore.Qt.LeftButton))).length() < QtWidgets.QApplication.startDragDistance():
+ start = QPointF(event.buttonDownScreenPos(Qt.LeftButton))
+ if QLineF(event.screenPos(), start).length() < self._start_drag_distance:
return
- drag = QtGui.QDrag(event.widget())
- mime = QtCore.QMimeData()
+ drag = QDrag(event.widget())
+ mime = QMimeData()
drag.setMimeData(mime)
ColorItem.n += 1
- if ColorItem.n > 2 and QtCore.qrand() % 3 == 0:
- image = QtGui.QImage(':/images/head.png')
+ if ColorItem.n > 2 and random(3) == 0:
+ image = QImage(':/images/head.png')
mime.setImageData(image)
- drag.setPixmap(QtGui.QPixmap.fromImage(image).scaled(30,40))
- drag.setHotSpot(QtCore.QPoint(15, 30))
+ drag.setPixmap(QPixmap.fromImage(image).scaled(30, 40))
+ drag.setHotSpot(QPoint(15, 30))
else:
mime.setColorData(self.color)
- mime.setText("#%02x%02x%02x" % (self.color.red(), self.color.green(), self.color.blue()))
+ (r, g, b) = (self.color.red(), self.color.green(), self.color.blue())
+ mime.setText(f"#{r:02x}{g:02x}{b:02x}")
- pixmap = QtGui.QPixmap(34, 34)
- pixmap.fill(QtCore.Qt.white)
+ pixmap = QPixmap(34, 34)
+ pixmap.fill(Qt.white)
- painter = QtGui.QPainter(pixmap)
- painter.translate(15, 15)
- painter.setRenderHint(QtGui.QPainter.Antialiasing)
- self.paint(painter, None, None)
- painter.end()
+ with QPainter(pixmap) as painter:
+ painter.translate(15, 15)
+ painter.setRenderHint(QPainter.Antialiasing)
+ self.paint(painter, None, None)
pixmap.setMask(pixmap.createHeuristicMask())
drag.setPixmap(pixmap)
- drag.setHotSpot(QtCore.QPoint(15, 20))
+ drag.setHotSpot(QPoint(15, 20))
- drag.exec_()
- self.setCursor(QtCore.Qt.OpenHandCursor)
+ drag.exec()
+ self.setCursor(Qt.OpenHandCursor)
def mouseReleaseEvent(self, event):
- self.setCursor(QtCore.Qt.OpenHandCursor)
+ self.setCursor(Qt.OpenHandCursor)
-class RobotPart(QtWidgets.QGraphicsItem):
+class RobotPart(QGraphicsItem):
def __init__(self, parent=None):
- super(RobotPart, self).__init__(parent)
+ super().__init__(parent)
- self.color = QtGui.QColor(QtCore.Qt.lightGray)
+ self.color = QColor(Qt.lightGray)
self.pixmap = None
- self.dragOver = False
+ self._drag_over = False
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
- if event.mimeData().hasColor() or \
- (isinstance(self, RobotHead) and event.mimeData().hasImage()):
+ if (event.mimeData().hasColor()
+ or (isinstance(self, RobotHead) and event.mimeData().hasImage())):
event.setAccepted(True)
- self.dragOver = True
+ self._drag_over = True
self.update()
else:
event.setAccepted(False)
def dragLeaveEvent(self, event):
- self.dragOver = False
+ self._drag_over = False
self.update()
def dropEvent(self, event):
- self.dragOver = False
+ self._drag_over = False
if event.mimeData().hasColor():
- self.color = QtGui.QColor(event.mimeData().colorData())
+ self.color = QColor(event.mimeData().colorData())
elif event.mimeData().hasImage():
- self.pixmap = QtGui.QPixmap(event.mimeData().imageData())
+ self.pixmap = QPixmap(event.mimeData().imageData())
self.update()
class RobotHead(RobotPart):
def boundingRect(self):
- return QtCore.QRectF(-15, -50, 30, 50)
+ return QRectF(-15, -50, 30, 50)
def paint(self, painter, option, widget=None):
if not self.pixmap:
- painter.setBrush(self.dragOver and self.color.lighter(130)
- or self.color)
- painter.drawRoundedRect(-10, -30, 20, 30, 25, 25,
- QtCore.Qt.RelativeSize)
- painter.setBrush(QtCore.Qt.white)
+ painter.setBrush(self._drag_over and self.color.lighter(130) or self.color)
+ painter.drawRoundedRect(-10, -30, 20, 30, 25, 25, Qt.RelativeSize)
+ painter.setBrush(Qt.white)
painter.drawEllipse(-7, -3 - 20, 7, 7)
painter.drawEllipse(0, -3 - 20, 7, 7)
- painter.setBrush(QtCore.Qt.black)
+ painter.setBrush(Qt.black)
painter.drawEllipse(-5, -1 - 20, 2, 2)
painter.drawEllipse(2, -1 - 20, 2, 2)
- painter.setPen(QtGui.QPen(QtCore.Qt.black, 2))
- painter.setBrush(QtCore.Qt.NoBrush)
+ painter.setPen(QPen(Qt.black, 2))
+ painter.setBrush(Qt.NoBrush)
painter.drawArc(-6, -2 - 20, 12, 15, 190 * 16, 160 * 16)
else:
painter.scale(.2272, .2824)
- painter.drawPixmap(QtCore.QPointF(-15*4.4, -50*3.54), self.pixmap)
+ painter.drawPixmap(QPointF(-15 * 4.4, -50 * 3.54), self.pixmap)
class RobotTorso(RobotPart):
def boundingRect(self):
- return QtCore.QRectF(-30, -20, 60, 60)
+ return QRectF(-30, -20, 60, 60)
def paint(self, painter, option, widget=None):
- painter.setBrush(self.dragOver and self.color.lighter(130)
- or self.color)
- painter.drawRoundedRect(-20, -20, 40, 60, 25, 25,
- QtCore.Qt.RelativeSize)
+ painter.setBrush(self._drag_over and self.color.lighter(130)
+ or self.color)
+ painter.drawRoundedRect(-20, -20, 40, 60, 25, 25, Qt.RelativeSize)
painter.drawEllipse(-25, -20, 20, 20)
painter.drawEllipse(5, -20, 20, 20)
painter.drawEllipse(-20, 22, 20, 20)
@@ -191,49 +163,49 @@ class RobotTorso(RobotPart):
class RobotLimb(RobotPart):
def boundingRect(self):
- return QtCore.QRectF(-5, -5, 40, 10)
+ return QRectF(-5, -5, 40, 10)
def paint(self, painter, option, widget=None):
- painter.setBrush(self.dragOver and self.color.lighter(130) or self.color)
+ painter.setBrush(self._drag_over and self.color.lighter(130) or self.color)
painter.drawRoundedRect(self.boundingRect(), 50, 50,
- QtCore.Qt.RelativeSize)
+ Qt.RelativeSize)
painter.drawEllipse(-5, -5, 10, 10)
class Robot(RobotPart):
def __init__(self):
- super(Robot, self).__init__()
-
- self.torsoItem = RobotTorso(self)
- self.headItem = RobotHead(self.torsoItem)
- self.upperLeftArmItem = RobotLimb(self.torsoItem)
- self.lowerLeftArmItem = RobotLimb(self.upperLeftArmItem)
- self.upperRightArmItem = RobotLimb(self.torsoItem)
- self.lowerRightArmItem = RobotLimb(self.upperRightArmItem)
- self.upperRightLegItem = RobotLimb(self.torsoItem)
- self.lowerRightLegItem = RobotLimb(self.upperRightLegItem)
- self.upperLeftLegItem = RobotLimb(self.torsoItem)
- self.lowerLeftLegItem = RobotLimb(self.upperLeftLegItem)
-
- self.timeline = QtCore.QTimeLine()
+ super().__init__()
+
+ self.torsoItem = RobotTorso(self)
+ self.headItem = RobotHead(self.torsoItem)
+ self.upperLeftArmItem = RobotLimb(self.torsoItem)
+ self.lowerLeftArmItem = RobotLimb(self.upperLeftArmItem)
+ self._upper_right_arm_item = RobotLimb(self.torsoItem)
+ self._lower_right_arm_item = RobotLimb(self._upper_right_arm_item)
+ self._upper_right_leg_item = RobotLimb(self.torsoItem)
+ self._lower_right_leg_item = RobotLimb(self._upper_right_leg_item)
+ self.upperLeftLegItem = RobotLimb(self.torsoItem)
+ self.lowerLeftLegItem = RobotLimb(self.upperLeftLegItem)
+
+ self.timeline = QTimeLine()
settings = [
- # item position rotation at
- # x y time 0 / 1
- ( self.headItem, 0, -18, 20, -20 ),
- ( self.upperLeftArmItem, -15, -10, 190, 180 ),
- ( self.lowerLeftArmItem, 30, 0, 50, 10 ),
- ( self.upperRightArmItem, 15, -10, 300, 310 ),
- ( self.lowerRightArmItem, 30, 0, 0, -70 ),
- ( self.upperRightLegItem, 10, 32, 40, 120 ),
- ( self.lowerRightLegItem, 30, 0, 10, 50 ),
- ( self.upperLeftLegItem, -10, 32, 150, 80 ),
- ( self.lowerLeftLegItem, 30, 0, 70, 10 ),
- ( self.torsoItem, 0, 0, 5, -20 )
+ # item position rotation at
+ # x y time 0 / 1
+ (self.headItem, 0, -18, 20, -20), # noqa: E241
+ (self.upperLeftArmItem, -15, -10, 190, 180), # noqa: E241
+ (self.lowerLeftArmItem, 30, 0, 50, 10), # noqa: E241
+ (self._upper_right_arm_item, 15, -10, 300, 310), # noqa: E241
+ (self._lower_right_arm_item, 30, 0, 0, -70), # noqa: E241
+ (self._upper_right_leg_item, 10, 32, 40, 120), # noqa: E241
+ (self._lower_right_leg_item, 30, 0, 10, 50), # noqa: E241
+ (self.upperLeftLegItem, -10, 32, 150, 80), # noqa: E241
+ (self.lowerLeftLegItem, 30, 0, 70, 10), # noqa: E241
+ (self.torsoItem, 0, 0, 5, -20) # noqa: E241
]
self.animations = []
for item, pos_x, pos_y, rotation1, rotation2 in settings:
- item.setPos(pos_x,pos_y)
- animation = QtWidgets.QGraphicsItemAnimation()
+ item.setPos(pos_x, pos_y)
+ animation = QGraphicsItemAnimation()
animation.setItem(item)
animation.setTimeLine(self.timeline)
animation.setRotationAt(0, rotation1)
@@ -242,45 +214,40 @@ class Robot(RobotPart):
self.animations[0].setScaleAt(1, 1.1, 1.1)
self.timeline.setUpdateInterval(1000 / 25)
- self.timeline.setCurveShape(QtCore.QTimeLine.SineCurve)
+ curve = QEasingCurve(QEasingCurve.SineCurve)
+ self.timeline.setEasingCurve(curve)
self.timeline.setLoopCount(0)
self.timeline.setDuration(2000)
self.timeline.start()
def boundingRect(self):
- return QtCore.QRectF()
+ return QRectF()
def paint(self, painter, option, widget=None):
pass
-if __name__== '__main__':
-
- import sys
- import math
-
- app = QtWidgets.QApplication(sys.argv)
-
- QtCore.qsrand(QtCore.QTime(0, 0, 0).secsTo(QtCore.QTime.currentTime()))
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
- scene = QtWidgets.QGraphicsScene(-200, -200, 400, 400)
+ scene = QGraphicsScene(-200, -200, 400, 400)
for i in range(10):
item = ColorItem()
- angle = i*6.28 / 10.0
- item.setPos(math.sin(angle)*150, math.cos(angle)*150)
+ angle = i * 2.0 * math.pi / 10.0
+ item.setPos(math.sin(angle) * 150, math.cos(angle) * 150)
scene.addItem(item)
robot = Robot()
- robot.setTransform(QtGui.QTransform().scale(1.2, 1.2))
+ robot.setTransform(QTransform().scale(1.2, 1.2))
robot.setPos(0, -20)
scene.addItem(robot)
- view = QtWidgets.QGraphicsView(scene)
- view.setRenderHint(QtGui.QPainter.Antialiasing)
- view.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate)
- view.setBackgroundBrush(QtGui.QColor(230, 200, 167))
+ view = QGraphicsView(scene)
+ view.setRenderHint(QPainter.Antialiasing)
+ view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
+ view.setBackgroundBrush(QColor(230, 200, 167))
view.setWindowTitle("Drag and Drop Robot")
view.show()
- sys.exit(app.exec_())
+ sys.exit(app.exec())
diff --git a/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject
index 587484a97..f31851b91 100644
--- a/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject
+++ b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject
@@ -1,3 +1,3 @@
{
- "files": ["dragdroprobot.qrc", "dragdroprobot_rc.py", "dragdroprobot.py"]
+ "files": ["dragdroprobot.qrc", "dragdroprobot.py"]
}
diff --git a/examples/widgets/graphicsview/dragdroprobot/dragdroprobot_rc.py b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot_rc.py
index 23d346301..b0e29d413 100644
--- a/examples/widgets/graphicsview/dragdroprobot/dragdroprobot_rc.py
+++ b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot_rc.py
@@ -1,9 +1,9 @@
# 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:|\
@@ -963,7 +963,7 @@ qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01e\xaf\x16\xd2\x9d\
+\x00\x00\x01z\xe7\xee'\x09\
"
def qInitResources():
diff --git a/examples/widgets/graphicsview/elasticnodes.py b/examples/widgets/graphicsview/elasticnodes.py
deleted file mode 100644
index 48feffc85..000000000
--- a/examples/widgets/graphicsview/elasticnodes.py
+++ /dev/null
@@ -1,413 +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$
-##
-#############################################################################
-
-import sys
-import weakref
-import math
-from PySide2 import QtCore, QtGui, QtWidgets
-
-
-class Edge(QtWidgets.QGraphicsItem):
- Pi = math.pi
- TwoPi = 2.0 * Pi
-
- Type = QtWidgets.QGraphicsItem.UserType + 2
-
- def __init__(self, sourceNode, destNode):
- QtWidgets.QGraphicsItem.__init__(self)
-
- self.arrowSize = 10.0
- self.sourcePoint = QtCore.QPointF()
- self.destPoint = QtCore.QPointF()
- self.setAcceptedMouseButtons(QtCore.Qt.NoButton)
- self.source = weakref.ref(sourceNode)
- self.dest = weakref.ref(destNode)
- self.source().addEdge(self)
- self.dest().addEdge(self)
- self.adjust()
-
- def type(self):
- return Edge.Type
-
- def sourceNode(self):
- return self.source()
-
- def setSourceNode(self, node):
- self.source = weakref.ref(node)
- self.adjust()
-
- def destNode(self):
- return self.dest()
-
- def setDestNode(self, node):
- self.dest = weakref.ref(node)
- self.adjust()
-
- def adjust(self):
- if not self.source() or not self.dest():
- return
-
- line = QtCore.QLineF(self.mapFromItem(self.source(), 0, 0), self.mapFromItem(self.dest(), 0, 0))
- length = line.length()
-
- if length == 0.0:
- return
-
- edgeOffset = QtCore.QPointF((line.dx() * 10) / length, (line.dy() * 10) / length)
-
- self.prepareGeometryChange()
- self.sourcePoint = line.p1() + edgeOffset
- self.destPoint = line.p2() - edgeOffset
-
- def boundingRect(self):
- if not self.source() or not self.dest():
- return QtCore.QRectF()
-
- penWidth = 1
- extra = (penWidth + self.arrowSize) / 2.0
-
- return QtCore.QRectF(self.sourcePoint,
- QtCore.QSizeF(self.destPoint.x() - self.sourcePoint.x(),
- self.destPoint.y() - self.sourcePoint.y())).normalized().adjusted(-extra, -extra, extra, extra)
-
- def paint(self, painter, option, widget):
- if not self.source() or not self.dest():
- return
-
- # Draw the line itself.
- line = QtCore.QLineF(self.sourcePoint, self.destPoint)
-
- if line.length() == 0.0:
- return
-
- painter.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
- painter.drawLine(line)
-
- # Draw the arrows if there's enough room.
- angle = math.acos(line.dx() / line.length())
- if line.dy() >= 0:
- angle = Edge.TwoPi - angle
-
- sourceArrowP1 = self.sourcePoint + QtCore.QPointF(math.sin(angle + Edge.Pi / 3) * self.arrowSize,
- math.cos(angle + Edge.Pi / 3) * self.arrowSize)
- sourceArrowP2 = self.sourcePoint + QtCore.QPointF(math.sin(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize,
- math.cos(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize)
- destArrowP1 = self.destPoint + QtCore.QPointF(math.sin(angle - Edge.Pi / 3) * self.arrowSize,
- math.cos(angle - Edge.Pi / 3) * self.arrowSize)
- destArrowP2 = self.destPoint + QtCore.QPointF(math.sin(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize,
- math.cos(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize)
-
- painter.setBrush(QtCore.Qt.black)
- painter.drawPolygon(QtGui.QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2]))
- painter.drawPolygon(QtGui.QPolygonF([line.p2(), destArrowP1, destArrowP2]))
-
-
-class Node(QtWidgets.QGraphicsItem):
- Type = QtWidgets.QGraphicsItem.UserType + 1
-
- def __init__(self, graphWidget):
- QtWidgets.QGraphicsItem.__init__(self)
-
- self.graph = weakref.ref(graphWidget)
- self.edgeList = []
- self.newPos = QtCore.QPointF()
- self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
- self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges)
- self.setCacheMode(self.DeviceCoordinateCache)
- self.setZValue(-1)
-
- def type(self):
- return Node.Type
-
- def addEdge(self, edge):
- self.edgeList.append(weakref.ref(edge))
- edge.adjust()
-
- def edges(self):
- return self.edgeList
-
- def calculateForces(self):
- if not self.scene() or self.scene().mouseGrabberItem() is self:
- self.newPos = self.pos()
- return
-
- # Sum up all forces pushing this item away.
- xvel = 0.0
- yvel = 0.0
- for item in self.scene().items():
- if not isinstance(item, Node):
- continue
-
- line = QtCore.QLineF(self.mapFromItem(item, 0, 0), QtCore.QPointF(0, 0))
- dx = line.dx()
- dy = line.dy()
- l = 2.0 * (dx * dx + dy * dy)
- if l > 0:
- xvel += (dx * 150.0) / l
- yvel += (dy * 150.0) / l
-
- # Now subtract all forces pulling items together.
- weight = (len(self.edgeList) + 1) * 10.0
- for edge in self.edgeList:
- if edge().sourceNode() is self:
- pos = self.mapFromItem(edge().destNode(), 0, 0)
- else:
- pos = self.mapFromItem(edge().sourceNode(), 0, 0)
- xvel += pos.x() / weight
- yvel += pos.y() / weight
-
- if QtCore.qAbs(xvel) < 0.1 and QtCore.qAbs(yvel) < 0.1:
- xvel = yvel = 0.0
-
- sceneRect = self.scene().sceneRect()
- self.newPos = self.pos() + QtCore.QPointF(xvel, yvel)
- self.newPos.setX(min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10))
- self.newPos.setY(min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))
-
- def advance(self):
- if self.newPos == self.pos():
- return False
-
- self.setPos(self.newPos)
- return True
-
- def boundingRect(self):
- adjust = 2.0
- return QtCore.QRectF(-10 - adjust, -10 - adjust,
- 23 + adjust, 23 + adjust)
-
- def shape(self):
- path = QtGui.QPainterPath()
- path.addEllipse(-10, -10, 20, 20)
- return path
-
- def paint(self, painter, option, widget):
- painter.setPen(QtCore.Qt.NoPen)
- painter.setBrush(QtCore.Qt.darkGray)
- painter.drawEllipse(-7, -7, 20, 20)
-
- gradient = QtGui.QRadialGradient(-3, -3, 10)
- if option.state & QtWidgets.QStyle.State_Sunken:
- gradient.setCenter(3, 3)
- gradient.setFocalPoint(3, 3)
- gradient.setColorAt(1, QtGui.QColor(QtCore.Qt.yellow).lighter(120))
- gradient.setColorAt(0, QtGui.QColor(QtCore.Qt.darkYellow).lighter(120))
- else:
- gradient.setColorAt(0, QtCore.Qt.yellow)
- gradient.setColorAt(1, QtCore.Qt.darkYellow)
-
- painter.setBrush(QtGui.QBrush(gradient))
- painter.setPen(QtGui.QPen(QtCore.Qt.black, 0))
- painter.drawEllipse(-10, -10, 20, 20)
-
- def itemChange(self, change, value):
- if change == QtWidgets.QGraphicsItem.ItemPositionChange:
- for edge in self.edgeList:
- edge().adjust()
- self.graph().itemMoved()
-
- return QtWidgets.QGraphicsItem.itemChange(self, change, value)
-
- def mousePressEvent(self, event):
- self.update()
- QtWidgets.QGraphicsItem.mousePressEvent(self, event)
-
- def mouseReleaseEvent(self, event):
- self.update()
- QtWidgets.QGraphicsItem.mouseReleaseEvent(self, event)
-
-
-class GraphWidget(QtWidgets.QGraphicsView):
- def __init__(self):
- QtWidgets.QGraphicsView.__init__(self)
-
- self.timerId = 0
-
- scene = QtWidgets.QGraphicsScene(self)
- scene.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex)
- scene.setSceneRect(-200, -200, 400, 400)
- self.setScene(scene)
- self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground)
- self.setRenderHint(QtGui.QPainter.Antialiasing)
- self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
- self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter)
-
- node1 = Node(self)
- node2 = Node(self)
- node3 = Node(self)
- node4 = Node(self)
- self.centerNode = Node(self)
- node6 = Node(self)
- node7 = Node(self)
- node8 = Node(self)
- node9 = Node(self)
- scene.addItem(node1)
- scene.addItem(node2)
- scene.addItem(node3)
- scene.addItem(node4)
- scene.addItem(self.centerNode)
- scene.addItem(node6)
- scene.addItem(node7)
- scene.addItem(node8)
- scene.addItem(node9)
- scene.addItem(Edge(node1, node2))
- scene.addItem(Edge(node2, node3))
- scene.addItem(Edge(node2, self.centerNode))
- scene.addItem(Edge(node3, node6))
- scene.addItem(Edge(node4, node1))
- scene.addItem(Edge(node4, self.centerNode))
- scene.addItem(Edge(self.centerNode, node6))
- scene.addItem(Edge(self.centerNode, node8))
- scene.addItem(Edge(node6, node9))
- scene.addItem(Edge(node7, node4))
- scene.addItem(Edge(node8, node7))
- scene.addItem(Edge(node9, node8))
-
- node1.setPos(-50, -50)
- node2.setPos(0, -50)
- node3.setPos(50, -50)
- node4.setPos(-50, 0)
- self.centerNode.setPos(0, 0)
- node6.setPos(50, 0)
- node7.setPos(-50, 50)
- node8.setPos(0, 50)
- node9.setPos(50, 50)
-
- self.scale(0.8, 0.8)
- self.setMinimumSize(400, 400)
- self.setWindowTitle(self.tr("Elastic Nodes"))
-
- def itemMoved(self):
- if not self.timerId:
- self.timerId = self.startTimer(1000 / 25)
-
- def keyPressEvent(self, event):
- key = event.key()
-
- if key == QtCore.Qt.Key_Up:
- self.centerNode.moveBy(0, -20)
- elif key == QtCore.Qt.Key_Down:
- self.centerNode.moveBy(0, 20)
- elif key == QtCore.Qt.Key_Left:
- self.centerNode.moveBy(-20, 0)
- elif key == QtCore.Qt.Key_Right:
- self.centerNode.moveBy(20, 0)
- elif key == QtCore.Qt.Key_Plus:
- self.scaleView(1.2)
- elif key == QtCore.Qt.Key_Minus:
- self.scaleView(1 / 1.2)
- elif key == QtCore.Qt.Key_Space or key == QtCore.Qt.Key_Enter:
- for item in self.scene().items():
- if isinstance(item, Node):
- item.setPos(-150 + QtCore.qrand() % 300, -150 + QtCore.qrand() % 300)
- else:
- QtWidgets.QGraphicsView.keyPressEvent(self, event)
-
-
- def timerEvent(self, event):
- nodes = [item for item in self.scene().items() if isinstance(item, Node)]
-
- for node in nodes:
- node.calculateForces()
-
- itemsMoved = False
- for node in nodes:
- if node.advance():
- itemsMoved = True
-
- if not itemsMoved:
- self.killTimer(self.timerId)
- self.timerId = 0
-
- def wheelEvent(self, event):
- self.scaleView(math.pow(2.0, -event.delta() / 240.0))
-
- def drawBackground(self, painter, rect):
- # Shadow.
- sceneRect = self.sceneRect()
- rightShadow = QtCore.QRectF(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height())
- bottomShadow = QtCore.QRectF(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5)
- if rightShadow.intersects(rect) or rightShadow.contains(rect):
- painter.fillRect(rightShadow, QtCore.Qt.darkGray)
- if bottomShadow.intersects(rect) or bottomShadow.contains(rect):
- painter.fillRect(bottomShadow, QtCore.Qt.darkGray)
-
- # Fill.
- gradient = QtGui.QLinearGradient(sceneRect.topLeft(), sceneRect.bottomRight())
- gradient.setColorAt(0, QtCore.Qt.white)
- gradient.setColorAt(1, QtCore.Qt.lightGray)
- painter.fillRect(rect.intersected(sceneRect), QtGui.QBrush(gradient))
- painter.setBrush(QtCore.Qt.NoBrush)
- painter.drawRect(sceneRect)
-
- # Text.
- textRect = QtCore.QRectF(sceneRect.left() + 4, sceneRect.top() + 4,
- sceneRect.width() - 4, sceneRect.height() - 4)
- message = self.tr("Click and drag the nodes around, and zoom with the "
- "mouse wheel or the '+' and '-' keys")
-
- font = painter.font()
- font.setBold(True)
- font.setPointSize(14)
- painter.setFont(font)
- painter.setPen(QtCore.Qt.lightGray)
- painter.drawText(textRect.translated(2, 2), message)
- painter.setPen(QtCore.Qt.black)
- painter.drawText(textRect, message)
-
- def scaleView(self, scaleFactor):
- factor = self.matrix().scale(scaleFactor, scaleFactor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width()
-
- if factor < 0.07 or factor > 100:
- return
-
- self.scale(scaleFactor, scaleFactor)
-
-
-if __name__ == "__main__":
- app = QtWidgets.QApplication(sys.argv)
- QtCore.qsrand(QtCore.QTime(0,0,0).secsTo(QtCore.QTime.currentTime()))
-
- widget = GraphWidget()
- widget.show()
-
- sys.exit(app.exec_())
diff --git a/examples/widgets/graphicsview/elasticnodes/elasticnodes.py b/examples/widgets/graphicsview/elasticnodes/elasticnodes.py
new file mode 100644
index 000000000..90cb49626
--- /dev/null
+++ b/examples/widgets/graphicsview/elasticnodes/elasticnodes.py
@@ -0,0 +1,391 @@
+# Copyright (C) 2013 Riverbank Computing Limited.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+import weakref
+import math
+
+from PySide6.QtCore import (QLineF, QPointF, QRandomGenerator, QRectF, QSizeF,
+ Qt, qAbs)
+from PySide6.QtGui import (QColor, QBrush, QLinearGradient, QPainter, QPainterPath, QPen,
+ QPolygonF, QRadialGradient)
+from PySide6.QtWidgets import (QApplication, QGraphicsItem, QGraphicsScene,
+ QGraphicsView, QStyle)
+
+
+def random(boundary):
+ return QRandomGenerator.global_().bounded(boundary)
+
+
+class Edge(QGraphicsItem):
+
+ def __init__(self, sourceNode, destNode):
+ super().__init__()
+
+ self._arrow_size = 10.0
+ self._source_point = QPointF()
+ self._dest_point = QPointF()
+ self.setAcceptedMouseButtons(Qt.NoButton)
+ self.source = weakref.ref(sourceNode)
+ self.dest = weakref.ref(destNode)
+ self.source().add_edge(self)
+ self.dest().add_edge(self)
+ self.adjust()
+
+ def item_type(self):
+ return QGraphicsItem.UserType + 2
+
+ def source_node(self):
+ return self.source()
+
+ def set_source_node(self, node):
+ self.source = weakref.ref(node)
+ self.adjust()
+
+ def dest_node(self):
+ return self.dest()
+
+ def set_dest_node(self, node):
+ self.dest = weakref.ref(node)
+ self.adjust()
+
+ def adjust(self):
+ if not self.source() or not self.dest():
+ return
+
+ line = QLineF(self.mapFromItem(self.source(), 0, 0),
+ self.mapFromItem(self.dest(), 0, 0))
+ length = line.length()
+
+ if length == 0.0:
+ return
+
+ edge_offset = QPointF((line.dx() * 10) / length, (line.dy() * 10) / length)
+
+ self.prepareGeometryChange()
+ self._source_point = line.p1() + edge_offset
+ self._dest_point = line.p2() - edge_offset
+
+ def boundingRect(self):
+ if not self.source() or not self.dest():
+ return QRectF()
+
+ pen_width = 1
+ extra = (pen_width + self._arrow_size) / 2.0
+
+ width = self._dest_point.x() - self._source_point.x()
+ height = self._dest_point.y() - self._source_point.y()
+ rect = QRectF(self._source_point, QSizeF(width, height))
+ return rect.normalized().adjusted(-extra, -extra, extra, extra)
+
+ def paint(self, painter, option, widget):
+ if not self.source() or not self.dest():
+ return
+
+ # Draw the line itself.
+ line = QLineF(self._source_point, self._dest_point)
+
+ if line.length() == 0.0:
+ return
+
+ painter.setPen(QPen(Qt.black, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
+ painter.drawLine(line)
+
+ # Draw the arrows if there's enough room.
+ angle = math.acos(line.dx() / line.length())
+ if line.dy() >= 0:
+ angle = 2 * math.pi - angle
+
+ arrow_head1 = QPointF(math.sin(angle + math.pi / 3) * self._arrow_size,
+ math.cos(angle + math.pi / 3) * self._arrow_size)
+ source_arrow_p1 = self._source_point + arrow_head1
+ arrow_head2 = QPointF(math.sin(angle + math.pi - math.pi / 3) * self._arrow_size,
+ math.cos(angle + math.pi - math.pi / 3) * self._arrow_size)
+ source_arrow_p2 = self._source_point + arrow_head2
+
+ arrow_head1 = QPointF(math.sin(angle - math.pi / 3) * self._arrow_size,
+ math.cos(angle - math.pi / 3) * self._arrow_size)
+ dest_arrow_p1 = self._dest_point + arrow_head1
+ arrow_head2 = QPointF(math.sin(angle - math.pi + math.pi / 3) * self._arrow_size,
+ math.cos(angle - math.pi + math.pi / 3) * self._arrow_size)
+ dest_arrow_p2 = self._dest_point + arrow_head2
+
+ painter.setBrush(Qt.black)
+ painter.drawPolygon(QPolygonF([line.p1(), source_arrow_p1, source_arrow_p2]))
+ painter.drawPolygon(QPolygonF([line.p2(), dest_arrow_p1, dest_arrow_p2]))
+
+
+class Node(QGraphicsItem):
+
+ def __init__(self, graphWidget):
+ super().__init__()
+
+ self.graph = weakref.ref(graphWidget)
+ self._edge_list = []
+ self._new_pos = QPointF()
+ self.setFlag(QGraphicsItem.ItemIsMovable)
+ self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
+ self.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
+ self.setZValue(-1)
+
+ def item_type(self):
+ return QGraphicsItem.UserType + 1
+
+ def add_edge(self, edge):
+ self._edge_list.append(weakref.ref(edge))
+ edge.adjust()
+
+ def edges(self):
+ return self._edge_list
+
+ def calculate_forces(self):
+ if not self.scene() or self.scene().mouseGrabberItem() is self:
+ self._new_pos = self.pos()
+ return
+
+ # Sum up all forces pushing this item away.
+ xvel = 0.0
+ yvel = 0.0
+ for item in self.scene().items():
+ if not isinstance(item, Node):
+ continue
+
+ line = QLineF(self.mapFromItem(item, 0, 0), QPointF(0, 0))
+ dx = line.dx()
+ dy = line.dy()
+ l = 2.0 * (dx * dx + dy * dy) # noqa: E741
+ if l > 0:
+ xvel += (dx * 150.0) / l
+ yvel += (dy * 150.0) / l
+
+ # Now subtract all forces pulling items together.
+ weight = (len(self._edge_list) + 1) * 10.0
+ for edge in self._edge_list:
+ if edge().source_node() is self:
+ pos = self.mapFromItem(edge().dest_node(), 0, 0)
+ else:
+ pos = self.mapFromItem(edge().source_node(), 0, 0)
+ xvel += pos.x() / weight
+ yvel += pos.y() / weight
+
+ if qAbs(xvel) < 0.1 and qAbs(yvel) < 0.1:
+ xvel = yvel = 0.0
+
+ scene_rect = self.scene().sceneRect()
+ self._new_pos = self.pos() + QPointF(xvel, yvel)
+ self._new_pos.setX(min(max(self._new_pos.x(), scene_rect.left() + 10),
+ scene_rect.right() - 10))
+ self._new_pos.setY(min(max(self._new_pos.y(), scene_rect.top() + 10),
+ scene_rect.bottom() - 10))
+
+ def advance(self):
+ if self._new_pos == self.pos():
+ return False
+
+ self.setPos(self._new_pos)
+ return True
+
+ def boundingRect(self):
+ adjust = 2.0
+ return QRectF(-10 - adjust, -10 - adjust,
+ 23 + adjust, 23 + adjust)
+
+ def shape(self):
+ path = QPainterPath()
+ path.addEllipse(-10, -10, 20, 20)
+ return path
+
+ def paint(self, painter, option, widget):
+ painter.setPen(Qt.NoPen)
+ painter.setBrush(Qt.darkGray)
+ painter.drawEllipse(-7, -7, 20, 20)
+
+ gradient = QRadialGradient(-3, -3, 10)
+ if option.state & QStyle.State_Sunken:
+ gradient.setCenter(3, 3)
+ gradient.setFocalPoint(3, 3)
+ gradient.setColorAt(1, QColor(Qt.yellow).lighter(120))
+ gradient.setColorAt(0, QColor(Qt.darkYellow).lighter(120))
+ else:
+ gradient.setColorAt(0, Qt.yellow)
+ gradient.setColorAt(1, Qt.darkYellow)
+
+ painter.setBrush(QBrush(gradient))
+ painter.setPen(QPen(Qt.black, 0))
+ painter.drawEllipse(-10, -10, 20, 20)
+
+ def itemChange(self, change, value):
+ if change == QGraphicsItem.ItemPositionChange:
+ for edge in self._edge_list:
+ edge().adjust()
+ self.graph().item_moved()
+
+ return QGraphicsItem.itemChange(self, change, value)
+
+ def mousePressEvent(self, event):
+ self.update()
+ QGraphicsItem.mousePressEvent(self, event)
+
+ def mouseReleaseEvent(self, event):
+ self.update()
+ QGraphicsItem.mouseReleaseEvent(self, event)
+
+
+class GraphWidget(QGraphicsView):
+ def __init__(self):
+ super().__init__()
+
+ self._timer_id = 0
+
+ scene = QGraphicsScene(self)
+ scene.setItemIndexMethod(QGraphicsScene.NoIndex)
+ scene.setSceneRect(-200, -200, 400, 400)
+ self.setScene(scene)
+ self.setCacheMode(QGraphicsView.CacheBackground)
+ self.setRenderHint(QPainter.Antialiasing)
+ self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
+ self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
+
+ node1 = Node(self)
+ node2 = Node(self)
+ node3 = Node(self)
+ node4 = Node(self)
+ self._center_node = Node(self)
+ node6 = Node(self)
+ node7 = Node(self)
+ node8 = Node(self)
+ node9 = Node(self)
+ scene.addItem(node1)
+ scene.addItem(node2)
+ scene.addItem(node3)
+ scene.addItem(node4)
+ scene.addItem(self._center_node)
+ scene.addItem(node6)
+ scene.addItem(node7)
+ scene.addItem(node8)
+ scene.addItem(node9)
+ scene.addItem(Edge(node1, node2))
+ scene.addItem(Edge(node2, node3))
+ scene.addItem(Edge(node2, self._center_node))
+ scene.addItem(Edge(node3, node6))
+ scene.addItem(Edge(node4, node1))
+ scene.addItem(Edge(node4, self._center_node))
+ scene.addItem(Edge(self._center_node, node6))
+ scene.addItem(Edge(self._center_node, node8))
+ scene.addItem(Edge(node6, node9))
+ scene.addItem(Edge(node7, node4))
+ scene.addItem(Edge(node8, node7))
+ scene.addItem(Edge(node9, node8))
+
+ node1.setPos(-50, -50)
+ node2.setPos(0, -50)
+ node3.setPos(50, -50)
+ node4.setPos(-50, 0)
+ self._center_node.setPos(0, 0)
+ node6.setPos(50, 0)
+ node7.setPos(-50, 50)
+ node8.setPos(0, 50)
+ node9.setPos(50, 50)
+
+ self.scale(0.8, 0.8)
+ self.setMinimumSize(400, 400)
+ self.setWindowTitle(self.tr("Elastic Nodes"))
+
+ def item_moved(self):
+ if not self._timer_id:
+ self._timer_id = self.startTimer(1000 / 25)
+
+ def keyPressEvent(self, event):
+ key = event.key()
+
+ if key == Qt.Key_Up:
+ self._center_node.moveBy(0, -20)
+ elif key == Qt.Key_Down:
+ self._center_node.moveBy(0, 20)
+ elif key == Qt.Key_Left:
+ self._center_node.moveBy(-20, 0)
+ elif key == Qt.Key_Right:
+ self._center_node.moveBy(20, 0)
+ elif key == Qt.Key_Plus:
+ self.scale_view(1.2)
+ elif key == Qt.Key_Minus:
+ self.scale_view(1 / 1.2)
+ elif key == Qt.Key_Space or key == Qt.Key_Enter:
+ for item in self.scene().items():
+ if isinstance(item, Node):
+ item.setPos(-150 + random(300), -150 + random(300))
+ else:
+ QGraphicsView.keyPressEvent(self, event)
+
+ def timerEvent(self, event):
+ nodes = [item for item in self.scene().items() if isinstance(item, Node)]
+
+ for node in nodes:
+ node.calculate_forces()
+
+ items_moved = False
+ for node in nodes:
+ if node.advance():
+ items_moved = True
+
+ if not items_moved:
+ self.killTimer(self._timer_id)
+ self._timer_id = 0
+
+ def wheelEvent(self, event):
+ delta = event.angleDelta().y()
+ self.scale_view(math.pow(2.0, -delta / 240.0))
+
+ def draw_background(self, painter, rect):
+ # Shadow.
+ scene_rect = self.sceneRect()
+ right_shadow = QRectF(scene_rect.right(), scene_rect.top() + 5,
+ 5, scene_rect.height())
+ bottom_shadow = QRectF(scene_rect.left() + 5, scene_rect.bottom(),
+ scene_rect.width(), 5)
+ if right_shadow.intersects(rect) or right_shadow.contains(rect):
+ painter.fillRect(right_shadow, Qt.darkGray)
+ if bottom_shadow.intersects(rect) or bottom_shadow.contains(rect):
+ painter.fillRect(bottom_shadow, Qt.darkGray)
+
+ # Fill.
+ gradient = QLinearGradient(scene_rect.topLeft(), scene_rect.bottomRight())
+ gradient.setColorAt(0, Qt.white)
+ gradient.setColorAt(1, Qt.lightGray)
+ painter.fillRect(rect.intersected(scene_rect), QBrush(gradient))
+ painter.setBrush(Qt.NoBrush)
+ painter.drawRect(scene_rect)
+
+ # Text.
+ text_rect = QRectF(scene_rect.left() + 4, scene_rect.top() + 4,
+ scene_rect.width() - 4, scene_rect.height() - 4)
+ message = self.tr("Click and drag the nodes around, and zoom with the "
+ "mouse wheel or the '+' and '-' keys")
+
+ font = painter.font()
+ font.setBold(True)
+ font.setPointSize(14)
+ painter.setFont(font)
+ painter.setPen(Qt.lightGray)
+ painter.drawText(text_rect.translated(2, 2), message)
+ painter.setPen(Qt.black)
+ painter.drawText(text_rect, message)
+
+ def scale_view(self, scaleFactor):
+ factor = self.transform().scale(scaleFactor, scaleFactor).mapRect(
+ QRectF(0, 0, 1, 1)).width()
+
+ if factor < 0.07 or factor > 100:
+ return
+
+ self.scale(scaleFactor, scaleFactor)
+
+
+if __name__ == "__main__":
+ app = QApplication(sys.argv)
+
+ widget = GraphWidget()
+ widget.show()
+
+ sys.exit(app.exec())
diff --git a/examples/widgets/graphicsview/elasticnodes/elasticnodes.pyproject b/examples/widgets/graphicsview/elasticnodes/elasticnodes.pyproject
new file mode 100644
index 000000000..f6083e795
--- /dev/null
+++ b/examples/widgets/graphicsview/elasticnodes/elasticnodes.pyproject
@@ -0,0 +1,3 @@
+{
+ "files": ["elasticnodes.py"]
+}
diff --git a/examples/widgets/graphicsview/graphicsview.pyproject b/examples/widgets/graphicsview/graphicsview.pyproject
deleted file mode 100644
index 007d36bd2..000000000
--- a/examples/widgets/graphicsview/graphicsview.pyproject
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "files": ["elasticnodes.py", "anchorlayout.py"]
-}