问题
I am currently building an interactive canvas using PyQt5 and Graphicscene, so far modifying the codes found on those posts:
- PySide Node Graph connect items
- How to draw a line from mouse to a point in PyQt5?
I have made two separates examples of what I would like , but so far I have not been able to merge the two into a single code.
The first code I inserts a node and corresponding edge in the position clicked on the screen. Begins and ends with a double click of the left button of the mouse.
import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *
class WindowClass(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.view = ViewClass()
self.setCentralWidget(self.view)
class ViewClass(QGraphicsView):
def __init__(self, parent=None):
QGraphicsView.__init__(self, parent)
self.s = SceneClass()
self.setScene(self.s)
self.setRenderHint(QPainter.Antialiasing)
class SceneClass(QGraphicsScene):
def __init__(self, parent=None):
QGraphicsScene.__init__(self, QRectF(-1000, -1000, 2000, 2000), parent)
self.node_start = None
self.node_end = None
self.pos = None
self.pos_end = None
def mouseDoubleClickEvent(self, event):
if event.button() == Qt.LeftButton and self.node_start is None:
node = Node()
self.addItem(node)
node.setPos(event.scenePos() + QPointF(10, 10))
self.node_start = node
else:
self.node_start = None
def mouseMoveEvent(self, event):
super(SceneClass, self).mouseMoveEvent(event)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton and self.node_start:
"nodo final"
node = Node()
self.addItem(node)
node.setPos(event.scenePos() + QPointF(10, 10))
self.node_end = node
edge = Edge(self.node_start, self.node_end)
self.addItem(edge)
"nodo final se convierte en nodo inicial"
self.node_start = self.node_end
super(SceneClass, self).mousePressEvent(event)
class Node(QGraphicsEllipseItem):
def __init__(self, rect=QRectF(-20, -20, 20, 20), parent=None):
QGraphicsEllipseItem.__init__(self, rect, parent)
self.edges = []
self.setZValue(1)
self.setBrush(Qt.darkGray)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
def addEdge(self, edge):
self.edges.append(edge)
def itemChange(self, change, value):
if change == QGraphicsItem.ItemSelectedChange:
self.setBrush(Qt.green if value else Qt.darkGray)
if change == QGraphicsItem.ItemPositionHasChanged:
for edge in self.edges:
edge.adjust()
return QGraphicsItem.itemChange(self, change, value)
class Edge(QGraphicsLineItem):
def __init__(self, source, dest, parent=None):
QGraphicsLineItem.__init__(self, parent)
self.source = source
self.dest = dest
self.source.addEdge(self)
self.dest.addEdge(self)
self.setPen(QPen(Qt.red, 3))
self.adjust()
def adjust(self):
self.prepareGeometryChange()
self.setLine(QLineF(self.dest.pos() + QPointF(-10, -10), self.source.pos() + QPointF(-10, -10)))
if __name__ == '__main__':
app = QApplication(sys.argv)
wd = WindowClass()
wd.show()
sys.exit(app.exec_())
The second code paints a line from the last position where the left mouse button was clicked to the current mouse position on the screen.
import sys
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt
class MouseTracker(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.setMouseTracking(True)
def initUI(self):
self.setGeometry(200, 200, 1000, 500)
self.setWindowTitle('Mouse Tracker')
self.label = QLabel(self)
self.label.resize(500, 40)
self.show()
self.pos = None
self.pos_end = None
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.pos_end = event.pos()
def mouseMoveEvent(self, event):
self.pos = event.pos()
self.update()
def paintEvent(self, event):
if self.pos and self.pos_end:
"Estilo de Linea"
pen = QPen(Qt.red)
pen.setWidth(3)
pen.setStyle(Qt.CustomDashLine)
pen.setDashPattern([10, 10])
pen.setJoinStyle(Qt.RoundJoin)
"Objeto de QPainter"
q = QPainter(self)
q.setRenderHint(QPainter.Antialiasing, True)
"Aplicar estilo de Linea"
q.setPen(pen)
"Dibujar Linea"
q.drawLine(self.pos.x(), self.pos.y(), self.pos_end.x(), self.pos_end.y())
app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())
The behavior I would like to see in mi GUI code is the union of the two meaning the following: being able to insert node with its corresponding edge by a left mouse click and then when the left mouse click is released start the QPaint line of the second code from the last node insert to the current position on the screen. I have tried to join the two code but the paintevent does not triggered when is written in any of the classes of the first code, even if ti is its own class.
回答1:
QPainter is the low-level tool used for painting and the different high-level tools use it as the Qt Graphics Framework, but in this case they should not be used.
In your case it is preferable to use the items since it simplifies the task:
class WindowClass(QMainWindow):
def __init__(self, parent=None):
super(WindowClass, self).__init__(parent)
view = QGraphicsView()
view.setMouseTracking(True)
view.setRenderHint(QPainter.Antialiasing)
scene = SceneClass(self)
view.setScene(scene)
self.setCentralWidget(view)
self.resize(640, 480)
class SceneClass(QGraphicsScene):
def __init__(self, parent=None):
super(SceneClass, self).__init__(QRectF(-1000, -1000, 2000, 2000), parent)
self._edge_item = None
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
node = Node()
node.setPos(event.scenePos())
self.addItem(node)
if self._edge_item:
self._edge_item.dst = node
self._edge_item = None
else:
self._edge_item = Edge()
self._edge_item.src = node
self.addItem(self._edge_item)
def mouseMoveEvent(self, event):
if self._edge_item:
self._edge_item.p2 = event.scenePos()
super(SceneClass, self).mouseMoveEvent(event)
class Node(QGraphicsEllipseItem):
def __init__(self, rect=QRectF(-10, -10, 20, 20), parent=None):
super(Node, self).__init__(rect, parent)
self.edges = []
self.setZValue(1)
self.setBrush(Qt.darkGray)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
def addEdge(self, edge):
self.edges.append(edge)
def itemChange(self, change, value):
if change == QGraphicsItem.ItemSelectedChange:
self.setBrush(Qt.green if value else Qt.darkGray)
if change == QGraphicsItem.ItemPositionHasChanged:
for edge in self.edges:
edge.adjust()
return super(Node, self).itemChange(change, value)
class Edge(QGraphicsLineItem):
def __init__(self, parent=None):
super(Edge, self).__init__(parent)
self.setPen(QPen(Qt.red, 3))
self._src = None
self._dst = None
@property
def src(self):
return self._src
@src.setter
def src(self, node):
self._src = node
self._src.addEdge(self)
self.adjust()
@property
def dst(self):
return self._dst
@dst.setter
def dst(self, node):
self._dst = node
self._dst.addEdge(self)
self.adjust()
@property
def p1(self):
return self.line().p1()
@p1.setter
def p1(self, p):
line = self.line()
line.setP1(p)
self.setLine(line)
@property
def p2(self):
return self.line().p2()
@p2.setter
def p2(self, p):
line = self.line()
line.setP2(p)
self.setLine(line)
def adjust(self):
self.prepareGeometryChange()
if self.src:
self.p1 = self.src.pos()
self.p2 = self.src.pos()
if self.dst:
self.p2 = self.dst.pos()
来源:https://stackoverflow.com/questions/61809809/join-qgraphicsitem-and-qpainter-in-same-graphicsscene