仓库地址 https://gitlab.com/pavel.krupala/pyqt-node-editor-tutorials.git
效果图
无
完成node之间的连接线 , 并移动的时候刷新连接线.
代码
-
node_editor_wnd.py
实例化连接线
from node_graphics_edge import *
#直线
EDGE_TYPE_DIRECT = 1
#三次方贝塞尔曲线
EDGE_TYPE_BEZIER = 2
DEBUG = True
class Edge:
def __init__(self, scene, start_socket, end_socket, edge_type=EDGE_TYPE_DIRECT):
self.scene = scene
self.start_socket = start_socket
self.end_socket = end_socket
self.start_socket.edge = self
if self.end_socket is not None:
self.end_socket.edge = self
# 看实例化传入的是需要哪种类型的连接线
self.grEdge = QDMGraphicsEdgeDirect(self) \
if edge_type == EDGE_TYPE_DIRECT \
else QDMGraphicsEdgeBezier(self)
# 刷新连接线位置
self.updatePositions()
if DEBUG: print("Edge: ", self.grEdge.posSource, "to", self.grEdge.posDestination)
self.scene.grScene.addItem(self.grEdge)
def updatePositions(self):
"""
刷新连接线位置
"""
source_pos = self.start_socket.getSocketPosition()
source_pos[0] += self.start_socket.node.grNode.pos().x()
source_pos[1] += self.start_socket.node.grNode.pos().y()
self.grEdge.setSource(*source_pos)
if self.end_socket is not None:
end_pos = self.end_socket.getSocketPosition()
end_pos[0] += self.end_socket.node.grNode.pos().x()
end_pos[1] += self.end_socket.node.grNode.pos().y()
self.grEdge.setDestination(*end_pos)
if DEBUG: print(" SS:", self.start_socket)
if DEBUG: print(" ES:", self.end_socket)
self.grEdge.update()
def remove_from_sockets(self):
if self.start_socket is not None:
self.start_socket.edge = None
if self.end_socket is not None:
self.end_socket.edge = None
self.end_socket = None
self.start_socket = None
def remove(self):
# revove1
self.remove_from_sockets()
# revove2
self.scene.grScene.removeItem(self.grEdge)
self.grEdge = None
# revove3
self.scene.removeEdge(self)
- node_graphics_edge.py
直线和曲线的样式细节
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class QDMGraphicsEdge(QGraphicsPathItem):
"""
连接线的样式基类
"""
def __init__(self, edge, parent=None):
super().__init__(parent)
self.edge = edge
self._color = QColor("#001000")
self._color_selected = QColor("#00ff00")
self._pen = QPen(self._color)
self._pen_selected = QPen(self._color_selected)
self._pen.setWidthF(2.0)
self._pen_selected.setWidthF(2.0)
self.setFlag(QGraphicsItem.ItemIsSelectable)
self.setZValue(-1)
self.posSource = [0, 0]
self.posDestination = [200, 100]
def setSource(self, x, y):
self.posSource = [x, y]
def setDestination(self, x, y):
self.posDestination = [x, y]
def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
self.updatePath()
painter.setPen(self._pen if not self.isSelected() else self._pen_selected)
painter.setBrush(Qt.NoBrush)
painter.drawPath(self.path())
def updatePath(self):
""" Will handle drawing QPainterPath from Point A to B """
raise NotImplemented("This method has to be overriden in a child class")
class QDMGraphicsEdgeDirect(QDMGraphicsEdge):
"""
直线
"""
def updatePath(self):
path = QPainterPath(QPointF(self.posSource[0], self.posSource[1]))
path.lineTo(self.posDestination[0], self.posDestination[1])
self.setPath(path)
class QDMGraphicsEdgeBezier(QDMGraphicsEdge):
"""
贝塞尔曲线
"""
def updatePath(self):
s = self.posSource
d = self.posDestination
dist = (d[0] - s[0]) * 0.5
if s[0] > d[0]: dist *= -1
path = QPainterPath(QPointF(self.posSource[0], self.posSource[1]))
path.cubicTo( s[0] + dist, s[1], d[0] - dist, d[1], self.posDestination[0], self.posDestination[1])
self.setPath(path)
但是这样只是初始化的时候用edge把node连接起来, node一移动 , 先的位置还是不变化 , 所以需要这样 , 增加mouseMoveEvent: