在同一个 GraphicsScene 中加入 QGraphicsItem 和 QPainter
Join QGraphicsItem and QPainter in same GraphicsScene
我目前正在使用 PyQt5 和 Graphicscene 构建交互式 canvas,目前正在修改在这些帖子中找到的代码:
我已经制作了两个单独的示例来说明我想要的内容,但到目前为止我还无法将两者合并为一个代码。
第一段代码我在屏幕上点击的位置插入一个节点和对应的边。以双击鼠标左键开始和结束。
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_())
第二个代码绘制一条线,从上次单击鼠标左键的位置到屏幕上的当前鼠标位置。
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_())
我希望在 mi GUI 代码中看到的行为是两者的结合,意思如下:能够通过单击鼠标左键插入节点及其相应的边,然后在释放鼠标左键时开始QPaint 行的第二个代码从最后一个节点插入到屏幕上的当前位置。我试图加入这两个代码,但是当在第一个代码的任何 classes 中写入时,即使 ti 是它自己的 class,也不会触发 paintevent。
QPainter 是用于绘画的低级工具,不同的高级工具将其用作 Qt 图形框架,但在这种情况下不应使用它们。
在您的情况下,最好使用这些项目,因为它可以简化任务:
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()
我目前正在使用 PyQt5 和 Graphicscene 构建交互式 canvas,目前正在修改在这些帖子中找到的代码:
我已经制作了两个单独的示例来说明我想要的内容,但到目前为止我还无法将两者合并为一个代码。
第一段代码我在屏幕上点击的位置插入一个节点和对应的边。以双击鼠标左键开始和结束。
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_())
第二个代码绘制一条线,从上次单击鼠标左键的位置到屏幕上的当前鼠标位置。
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_())
我希望在 mi GUI 代码中看到的行为是两者的结合,意思如下:能够通过单击鼠标左键插入节点及其相应的边,然后在释放鼠标左键时开始QPaint 行的第二个代码从最后一个节点插入到屏幕上的当前位置。我试图加入这两个代码,但是当在第一个代码的任何 classes 中写入时,即使 ti 是它自己的 class,也不会触发 paintevent。
QPainter 是用于绘画的低级工具,不同的高级工具将其用作 Qt 图形框架,但在这种情况下不应使用它们。
在您的情况下,最好使用这些项目,因为它可以简化任务:
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()