aboutsummaryrefslogtreecommitdiffstats
path: root/examples/widgets/graphicsview/diagramscene/diagramscene.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/widgets/graphicsview/diagramscene/diagramscene.py')
-rwxr-xr-xexamples/widgets/graphicsview/diagramscene/diagramscene.py825
1 files changed, 825 insertions, 0 deletions
diff --git a/examples/widgets/graphicsview/diagramscene/diagramscene.py b/examples/widgets/graphicsview/diagramscene/diagramscene.py
new file mode 100755
index 000000000..ea0af84f9
--- /dev/null
+++ b/examples/widgets/graphicsview/diagramscene/diagramscene.py
@@ -0,0 +1,825 @@
+#!/usr/bin/env python
+
+#############################################################################
+##
+## 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 PySide 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 math
+
+from PySide2 import QtCore, QtGui, QtWidgets
+
+import diagramscene_rc
+
+
+class Arrow(QtWidgets.QGraphicsLineItem):
+ def __init__(self, startItem, endItem, parent=None, scene=None):
+ super(Arrow, self).__init__(parent, scene)
+
+ self.arrowHead = QtGui.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))
+
+ def setColor(self, color):
+ self.myColor = color
+
+ def startItem(self):
+ return self.myStartItem
+
+ def endItem(self):
+ return self.myEndItem
+
+ 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)
+
+ def shape(self):
+ path = super(Arrow, self).shape()
+ path.addPolygon(self.arrowHead)
+ return path
+
+ def updatePosition(self):
+ line = QtCore.QLineF(self.mapFromItem(self.myStartItem, 0, 0), self.mapFromItem(self.myEndItem, 0, 0))
+ self.setLine(line)
+
+ def paint(self, painter, option, widget=None):
+ if (self.myStartItem.collidesWithItem(self.myEndItem)):
+ 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:
+ break
+ p1 = p2
+
+ self.setLine(QtCore.QLineF(intersectPoint, myStartItem.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)
+
+ self.arrowHead.clear()
+ for point in [line.p1(), arrowP1, arrowP2]:
+ self.arrowHead.append(point)
+
+ painter.drawLine(line)
+ painter.drawPolygon(self.arrowHead)
+ 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)
+
+
+class DiagramTextItem(QtWidgets.QGraphicsTextItem):
+ lostFocus = QtCore.Signal(QtWidgets.QGraphicsTextItem)
+
+ selectedChange = QtCore.Signal(QtWidgets.QGraphicsItem)
+
+ def __init__(self, parent=None, scene=None):
+ super(DiagramTextItem, self).__init__(parent, scene)
+
+ self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
+ self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable)
+
+ def itemChange(self, change, value):
+ if change == QtWidgets.QGraphicsItem.ItemSelectedChange:
+ self.selectedChange.emit(self)
+ return value
+
+ def focusOutEvent(self, event):
+ self.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
+ self.lostFocus.emit(self)
+ super(DiagramTextItem, self).focusOutEvent(event)
+
+ def mouseDoubleClickEvent(self, event):
+ if self.textInteractionFlags() == QtCore.Qt.NoTextInteraction:
+ self.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
+ super(DiagramTextItem, self).mouseDoubleClickEvent(event)
+
+
+class DiagramItem(QtWidgets.QGraphicsPolygonItem):
+ Step, Conditional, StartEnd, Io = range(4)
+
+ def __init__(self, diagramType, contextMenu, parent=None, scene=None):
+ super(DiagramItem, self).__init__(parent, scene)
+
+ self.arrows = []
+
+ self.diagramType = diagramType
+ self.myContextMenu = contextMenu
+
+ path = QtGui.QPainterPath()
+ if self.diagramType == 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)])
+ 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.setPolygon(self.myPolygon)
+ self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
+ self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
+
+ def removeArrow(self, arrow):
+ try:
+ self.arrows.remove(arrow)
+ except ValueError:
+ pass
+
+ def removeArrows(self):
+ for arrow in self.arrows[:]:
+ arrow.startItem().removeArrow(arrow)
+ arrow.endItem().removeArrow(arrow)
+ self.scene().removeItem(arrow)
+
+ def addArrow(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)
+ return pixmap
+
+ def contextMenuEvent(self, event):
+ self.scene().clearSelection()
+ self.setSelected(True)
+ self.myContextMenu.exec_(event.screenPos())
+
+ def itemChange(self, change, value):
+ if change == QtWidgets.QGraphicsItem.ItemPositionChange:
+ for arrow in self.arrows:
+ arrow.updatePosition()
+
+ return value
+
+
+class DiagramScene(QtWidgets.QGraphicsScene):
+ InsertItem, InsertLine, InsertText, MoveItem = range(4)
+
+ itemInserted = QtCore.Signal(DiagramItem)
+
+ textInserted = QtCore.Signal(QtWidgets.QGraphicsTextItem)
+
+ itemSelected = QtCore.Signal(QtWidgets.QGraphicsItem)
+
+ def __init__(self, itemMenu, parent=None):
+ super(DiagramScene, self).__init__(parent)
+
+ self.myItemMenu = itemMenu
+ self.myMode = self.MoveItem
+ self.myItemType = 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):
+ item = self.selectedItems()[0]
+ item.setColor(self.myLineColor)
+ self.update()
+
+ def setTextColor(self, color):
+ self.myTextColor = color
+ if self.isItemChange(DiagramTextItem):
+ item = self.selectedItems()[0]
+ item.setDefaultTextColor(self.myTextColor)
+
+ def setItemColor(self, color):
+ self.myItemColor = color
+ if self.isItemChange(DiagramItem):
+ item = self.selectedItems()[0]
+ item.setBrush(self.myItemColor)
+
+ def setFont(self, font):
+ self.myFont = font
+ if self.isItemChange(DiagramTextItem):
+ item = self.selectedItems()[0]
+ item.setFont(self.myFont)
+
+ def setMode(self, mode):
+ self.myMode = mode
+
+ def setItemType(self, type):
+ self.myItemType = type
+
+ def editorLostFocus(self, item):
+ cursor = item.textCursor()
+ cursor.clearSelection()
+ item.setTextCursor(cursor)
+
+ if not item.toPlainText():
+ self.removeItem(item)
+ item.deleteLater()
+
+ def mousePressEvent(self, mouseEvent):
+ if (mouseEvent.button() != QtCore.Qt.LeftButton):
+ return
+
+ if self.myMode == self.InsertItem:
+ item = DiagramItem(self.myItemType, self.myItemMenu)
+ item.setBrush(self.myItemColor)
+ 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.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)
+
+ 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:
+ 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)
+
+ 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)
+ arrow.setZValue(-1000.0)
+ self.addItem(arrow)
+ arrow.updatePosition()
+
+ self.line = None
+ super(DiagramScene, self).mouseReleaseEvent(mouseEvent)
+
+ def isItemChange(self, type):
+ for item in self.selectedItems():
+ if isinstance(item, type):
+ return True
+ return False
+
+
+class MainWindow(QtWidgets.QMainWindow):
+ InsertTextButton = 10
+
+ def __init__(self):
+ super(MainWindow, self).__init__()
+
+ self.createActions()
+ self.createMenus()
+ self.createToolBox()
+
+ 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.createToolbars()
+
+ layout = QtWidgets.QHBoxLayout()
+ layout.addWidget(self.toolBox)
+ self.view = QtWidgets.QGraphicsView(self.scene)
+ layout.addWidget(self.view)
+
+ self.widget = QtWidgets.QWidget()
+ self.widget.setLayout(layout)
+
+ self.setCentralWidget(self.widget)
+ self.setWindowTitle("Diagramscene")
+
+ def backgroundButtonGroupClicked(self, button):
+ buttons = self.backgroundButtonGroup.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')))
+ elif text == "White Grid":
+ self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background2.png')))
+ elif text == "Gray Grid":
+ self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background3.png')))
+ else:
+ self.scene.setBackgroundBrush(QtGui.QBrush(QtGui.QPixmap(':/images/background4.png')))
+
+ self.scene.update()
+ self.view.update()
+
+ def buttonGroupClicked(self, id):
+ buttons = self.buttonGroup.buttons()
+ for button in buttons:
+ if self.buttonGroup.button(id) != button:
+ button.setChecked(False)
+
+ if id == self.InsertTextButton:
+ self.scene.setMode(DiagramScene.InsertText)
+ else:
+ self.scene.setItemType(id)
+ self.scene.setMode(DiagramScene.InsertItem)
+
+ def deleteItem(self):
+ for item in self.scene.selectedItems():
+ if isinstance(item, DiagramItem):
+ item.removeArrows()
+ self.scene.removeItem(item)
+
+ def pointerGroupClicked(self, i):
+ self.scene.setMode(self.pointerTypeGroup.checkedId())
+
+ def bringToFront(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 sendToBack(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)
+ else:
+ font.setWeight(QtGui.QFont.Normal)
+ font.setItalic(self.italicAction.isChecked())
+ font.setUnderline(self.underlineAction.isChecked())
+
+ self.scene.setFont(font)
+
+ def itemSelected(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())
+
+ 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')
+ .scaled(30, 30)))
+ textButton.setIconSize(QtCore.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)
+
+ 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)
+ 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()
+ button.setText(text)
+ button.setIcon(QtGui.QIcon(image))
+ button.setIconSize(QtCore.QSize(50, 50))
+ button.setCheckable(True)
+ self.backgroundButtonGroup.addButton(button)
+
+ layout = QtWidgets.QGridLayout()
+ layout.addWidget(button, 0, 0, QtCore.Qt.AlignHCenter)
+ layout.addWidget(QtWidgets.QLabel(text), 1, 0, QtCore.Qt.AlignCenter)
+
+ widget = QtWidgets.QWidget()
+ widget.setLayout(layout)
+
+ return widget
+
+ def createCellWidget(self, text, diagramType):
+ item = DiagramItem(diagramType, self.itemMenu)
+ icon = QtGui.QIcon(item.image())
+
+ button = QtWidgets.QToolButton()
+ button.setIcon(icon)
+ button.setIconSize(QtCore.QSize(50, 50))
+ button.setCheckable(True)
+ self.buttonGroup.addButton(button, diagramType)
+
+ layout = QtWidgets.QGridLayout()
+ layout.addWidget(button, 0, 0, QtCore.Qt.AlignHCenter)
+ layout.addWidget(QtWidgets.QLabel(text), 1, 0, QtCore.Qt.AlignCenter)
+
+ widget = QtWidgets.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]
+ names = ["black", "white", "red", "blue", "yellow"]
+
+ colorMenu = QtWidgets.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)
+ if color == defaultColor:
+ colorMenu.setDefaultAction(action)
+ return colorMenu
+
+ 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()
+
+ return QtGui.QIcon(pixmap)
+
+ 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 QtGui.QIcon(pixmap)
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QtWidgets.QApplication(sys.argv)
+
+ mainWindow = MainWindow()
+ mainWindow.setGeometry(100, 100, 800, 500)
+ mainWindow.show()
+
+ sys.exit(app.exec_())