mirror of
https://gitee.com/py2cn/pyminer.git
synced 2024-12-02 11:48:14 +08:00
优化重叠情况
重构代码,添加流程图自动捕捉,并且像素可以调节,方便调整精度。
This commit is contained in:
parent
b52c6d3d19
commit
c914727edf
@ -3,7 +3,7 @@ from PyQt5.QtGui import QPolygonF, QPen, QPainterPath, QColor, QPainter, QBrush
|
|||||||
from PyQt5.QtWidgets import QGraphicsLineItem, QGraphicsItem, QGraphicsSceneMouseEvent, QGraphicsObject, \
|
from PyQt5.QtWidgets import QGraphicsLineItem, QGraphicsItem, QGraphicsSceneMouseEvent, QGraphicsObject, \
|
||||||
QStyleOptionGraphicsItem, QWidget, QGraphicsSceneHoverEvent
|
QStyleOptionGraphicsItem, QWidget, QGraphicsSceneHoverEvent
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Tuple, List
|
from typing import TYPE_CHECKING, Tuple, List, Callable
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .flowchart_widget import Node, PMGraphicsScene
|
from .flowchart_widget import Node, PMGraphicsScene
|
||||||
@ -11,9 +11,41 @@ if TYPE_CHECKING:
|
|||||||
COLOR_NORMAL = QColor(212, 227, 242)
|
COLOR_NORMAL = QColor(212, 227, 242)
|
||||||
COLOR_HOVER = QColor(255, 200, 00)
|
COLOR_HOVER = QColor(255, 200, 00)
|
||||||
COLOR_HOVER_PORT = QColor(0, 0, 50)
|
COLOR_HOVER_PORT = QColor(0, 0, 50)
|
||||||
|
COLOR_HOVER_MID_POINT = QColor(0, 0, 200)
|
||||||
COLOR_SELECTED = QColor(255, 255, 0)
|
COLOR_SELECTED = QColor(255, 255, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def round_position(point: QPointF, pixels=5):
|
||||||
|
x, y = point.x(), point.y()
|
||||||
|
x_cor, y_cor = round(x * 1.0 / pixels) * pixels, round(y * 1.0 / pixels) * pixels
|
||||||
|
return QPointF(x_cor, y_cor)
|
||||||
|
|
||||||
|
|
||||||
|
class PMGGraphicsLineItem(QGraphicsLineItem):
|
||||||
|
def __init__(self, line: QLineF):
|
||||||
|
super(PMGGraphicsLineItem, self).__init__(line)
|
||||||
|
self.callback = None
|
||||||
|
self.parent_line: 'CustomLine' = None
|
||||||
|
|
||||||
|
def bind_callback(self, parent_line: 'CustomLine' = None):
|
||||||
|
self.parent_line = parent_line
|
||||||
|
|
||||||
|
def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
|
||||||
|
'''
|
||||||
|
这里不能进行继承。一旦进行了继承,似乎会让下面所有的东西都收到信号,从而无法选定。
|
||||||
|
:param event:
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
super(PMGGraphicsLineItem, self).mousePressEvent(event)
|
||||||
|
self.parent_line.on_line_item_pressed(event, self)
|
||||||
|
|
||||||
|
def mouseDoubleClickEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
|
||||||
|
self.parent_line.add_mid_point(self, pos=event.scenePos())
|
||||||
|
|
||||||
|
def bind_mouse_clicked(self, callback: Callable):
|
||||||
|
self.callback = callback
|
||||||
|
|
||||||
|
|
||||||
class CustomLine(QGraphicsLineItem):
|
class CustomLine(QGraphicsLineItem):
|
||||||
'''
|
'''
|
||||||
CustomLine不是QObject,没有办法绑定信号,只能用回调函数的方式。
|
CustomLine不是QObject,没有办法绑定信号,只能用回调函数的方式。
|
||||||
@ -35,24 +67,61 @@ class CustomLine(QGraphicsLineItem):
|
|||||||
repaint_callback = None
|
repaint_callback = None
|
||||||
|
|
||||||
def __init__(self, start_port: 'CustomPort', end_port: 'CustomPort', canvas: 'PMGraphicsScene' = None,
|
def __init__(self, start_port: 'CustomPort', end_port: 'CustomPort', canvas: 'PMGraphicsScene' = None,
|
||||||
mid_points: 'List[CustomCenterPoint]' = None):
|
mid_points: 'List[CustomMidPoint]' = None):
|
||||||
super(CustomLine, self).__init__()
|
super(CustomLine, self).__init__()
|
||||||
self.color = COLOR_NORMAL
|
self.color = COLOR_NORMAL
|
||||||
self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) # 拖动
|
self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) # 拖动
|
||||||
self.start_port = start_port
|
self.start_port = start_port
|
||||||
self.end_port = end_port
|
self.end_port = end_port
|
||||||
|
if self not in start_port.connected_lines:
|
||||||
|
start_port.connected_lines.append(self)
|
||||||
|
if self not in end_port.connected_lines:
|
||||||
|
end_port.connected_lines.append(self)
|
||||||
self.line_Items: List['QGraphicsLineItem'] = []
|
self.line_Items: List['QGraphicsLineItem'] = []
|
||||||
self.center_points = mid_points if (mid_points is not None) else [CustomCenterPoint()]
|
self.center_points = mid_points if (mid_points is not None) else []
|
||||||
for p in self.center_points:
|
for p in self.center_points:
|
||||||
canvas.addItem(p)
|
canvas.addItem(p)
|
||||||
|
p.point_dragged.connect(self.refresh)
|
||||||
center_point = self.center_points[0]
|
p.line = self
|
||||||
center_point.point_dragged.connect(self.refresh)
|
|
||||||
canvas.signal_clear_selection.connect(self.on_clear_selection)
|
canvas.signal_clear_selection.connect(self.on_clear_selection)
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self.canvas = canvas
|
self.canvas = canvas
|
||||||
self.init_line_items()
|
self.init_line_items()
|
||||||
|
|
||||||
|
def remove_mid_point(self, mid_point: 'CustomMidPoint'):
|
||||||
|
index = self.center_points.index(mid_point)
|
||||||
|
point_to_remove = self.center_points.pop(index)
|
||||||
|
line_to_remove = self.line_Items.pop(index)
|
||||||
|
self.canvas.removeItem(point_to_remove)
|
||||||
|
self.canvas.removeItem(line_to_remove)
|
||||||
|
self.canvas.removeItem(mid_point)
|
||||||
|
self.refresh_line_items()
|
||||||
|
self.update()
|
||||||
|
self.canvas.graphics_view.viewport().update()
|
||||||
|
|
||||||
|
def add_mid_point(self, line_item: 'PMGGraphicsLineItem', pos: QPointF):
|
||||||
|
index = self.line_Items.index(line_item)
|
||||||
|
new_center_point = CustomMidPoint(pos, line=self)
|
||||||
|
self.canvas.addItem(new_center_point)
|
||||||
|
self.center_points.insert(index, new_center_point)
|
||||||
|
new_center_point.point_dragged.connect(self.refresh)
|
||||||
|
if index == 0:
|
||||||
|
last_pos = self.start_port.center_pos
|
||||||
|
else:
|
||||||
|
last_pos = self.center_points[index].center_pos
|
||||||
|
next_pos = new_center_point.center_pos
|
||||||
|
new_line_item = PMGGraphicsLineItem(QLineF(last_pos, next_pos))
|
||||||
|
new_line_item.bind_callback(self)
|
||||||
|
pen = QPen()
|
||||||
|
pen.setColor(self.color)
|
||||||
|
pen.setWidth(5)
|
||||||
|
new_line_item.setPen(pen)
|
||||||
|
self.canvas.addItem(new_line_item)
|
||||||
|
self.line_Items.insert(index, new_line_item)
|
||||||
|
self.refresh_line_items()
|
||||||
|
self.update()
|
||||||
|
self.canvas.graphics_view.viewport().update()
|
||||||
|
|
||||||
def init_line_items(self):
|
def init_line_items(self):
|
||||||
'''
|
'''
|
||||||
初始化线段,包括其中间节点。
|
初始化线段,包括其中间节点。
|
||||||
@ -62,8 +131,9 @@ class CustomLine(QGraphicsLineItem):
|
|||||||
last_pos = self.start_port.center_pos
|
last_pos = self.start_port.center_pos
|
||||||
for p in self.center_points:
|
for p in self.center_points:
|
||||||
pos = p.center_pos
|
pos = p.center_pos
|
||||||
line_item = QGraphicsLineItem(QLineF(last_pos, pos))
|
line_item = PMGGraphicsLineItem(QLineF(last_pos, pos))
|
||||||
line_item.mousePressEvent = self.on_line_item_pressed
|
# line_item.mousePressEvent = self.on_line_item_pressed
|
||||||
|
line_item.bind_callback(self)
|
||||||
pen = QPen()
|
pen = QPen()
|
||||||
pen.setColor(self.color)
|
pen.setColor(self.color)
|
||||||
pen.setWidth(5)
|
pen.setWidth(5)
|
||||||
@ -71,8 +141,9 @@ class CustomLine(QGraphicsLineItem):
|
|||||||
self.canvas.addItem(line_item)
|
self.canvas.addItem(line_item)
|
||||||
last_pos = pos
|
last_pos = pos
|
||||||
self.line_Items.append(line_item)
|
self.line_Items.append(line_item)
|
||||||
line_item = QGraphicsLineItem(QLineF(last_pos, self.end_port.center_pos))
|
line_item = PMGGraphicsLineItem(QLineF(last_pos, self.end_port.center_pos))
|
||||||
line_item.mousePressEvent = self.on_line_item_pressed
|
# line_item.mousePressEvent = self.on_line_item_pressed
|
||||||
|
line_item.bind_callback(self)
|
||||||
self.canvas.addItem(line_item)
|
self.canvas.addItem(line_item)
|
||||||
self.line_Items.append(line_item)
|
self.line_Items.append(line_item)
|
||||||
|
|
||||||
@ -93,19 +164,18 @@ class CustomLine(QGraphicsLineItem):
|
|||||||
line = QLineF(last_pos, self.end_port.center_pos)
|
line = QLineF(last_pos, self.end_port.center_pos)
|
||||||
self.line_Items[-1].setLine(line)
|
self.line_Items[-1].setLine(line)
|
||||||
|
|
||||||
def on_line_item_pressed(self, e: 'QGraphicsSceneMouseEvent'):
|
def on_line_item_pressed(self, e: 'QGraphicsSceneMouseEvent', line_item: 'CustomLine'):
|
||||||
'''
|
'''
|
||||||
当线段被点击时触发的事件。
|
当线段被点击时触发的事件。
|
||||||
:param e:
|
:param e:
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
print(e)
|
print(line_item)
|
||||||
|
|
||||||
if e.button() == Qt.LeftButton:
|
if e.button() == Qt.LeftButton:
|
||||||
if not e.modifiers() == Qt.ControlModifier:
|
if not e.modifiers() == Qt.ControlModifier:
|
||||||
self.canvas.signal_clear_selection.emit()
|
self.canvas.signal_clear_selection.emit()
|
||||||
self.setSelected(True)
|
self.canvas.select_item(self)
|
||||||
print(self.canvas.selectedItems())
|
print(self.canvas.selected_items)
|
||||||
self.color = COLOR_SELECTED
|
self.color = COLOR_SELECTED
|
||||||
|
|
||||||
def on_clear_selection(self):
|
def on_clear_selection(self):
|
||||||
@ -114,7 +184,7 @@ class CustomLine(QGraphicsLineItem):
|
|||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
self.color = COLOR_NORMAL
|
self.color = COLOR_NORMAL
|
||||||
self.setSelected(False)
|
self.canvas.unselect_item(self)
|
||||||
# self.update()
|
# self.update()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
@ -191,12 +261,36 @@ class CustomLine(QGraphicsLineItem):
|
|||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def on_delete(self):
|
||||||
|
'''
|
||||||
|
删除线对象
|
||||||
|
首先从起始和结束的端口的连线中删除这个线;
|
||||||
|
然后,从画布上移除自身所有的中间线段对象和中继点对象
|
||||||
|
从画布上删除自身;
|
||||||
|
从所有连线的列表中移除自身。
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
self.start_port.connected_lines.remove(self)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
self.end_port.connected_lines.remove(self)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
for line_item in self.line_Items:
|
||||||
|
self.canvas.removeItem(line_item)
|
||||||
|
for mid_item in self.center_points:
|
||||||
|
self.canvas.removeItem(mid_item)
|
||||||
|
self.canvas.removeItem(self)
|
||||||
|
self.canvas.lines.remove(self)
|
||||||
|
|
||||||
class CustomCenterPoint(QGraphicsObject):
|
|
||||||
|
class CustomMidPoint(QGraphicsObject):
|
||||||
point_dragged = pyqtSignal(QGraphicsObject)
|
point_dragged = pyqtSignal(QGraphicsObject)
|
||||||
|
|
||||||
def __init__(self, pos=None):
|
def __init__(self, pos: QPointF = None, line: 'CustomLine' = None):
|
||||||
super(CustomCenterPoint, self).__init__()
|
super(CustomMidPoint, self).__init__()
|
||||||
# self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) # 拖动
|
# self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable) # 拖动
|
||||||
self.setAcceptHoverEvents(True) # 接受鼠标悬停事件
|
self.setAcceptHoverEvents(True) # 接受鼠标悬停事件
|
||||||
self.relative_pos = (0, 0)
|
self.relative_pos = (0, 0)
|
||||||
@ -204,7 +298,12 @@ class CustomCenterPoint(QGraphicsObject):
|
|||||||
self.size = (10, 10)
|
self.size = (10, 10)
|
||||||
# self.line = line
|
# self.line = line
|
||||||
if pos is not None:
|
if pos is not None:
|
||||||
self.setPos(QPointF(*pos))
|
# self.setPos()
|
||||||
|
# if isinstance(pos,list) or isinstance(pos,tuple):
|
||||||
|
# self.setPos(pos[0],pos[1])
|
||||||
|
# else:
|
||||||
|
self.setPos(pos)
|
||||||
|
self.line = line
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
return QRectF(0, 0, self.size[0], self.size[1])
|
return QRectF(0, 0, self.size[0], self.size[1])
|
||||||
@ -214,13 +313,18 @@ class CustomCenterPoint(QGraphicsObject):
|
|||||||
return QPointF(self.x() + self.size[0] / 2, self.y() + self.size[1] / 2)
|
return QPointF(self.x() + self.size[0] / 2, self.y() + self.size[1] / 2)
|
||||||
|
|
||||||
def mouseMoveEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
|
def mouseMoveEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
|
||||||
|
'''
|
||||||
|
鼠标拖动时触发的事件。
|
||||||
|
:param event:
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
mouse_x, mouse_y = event.scenePos().x(), event.scenePos().y()
|
mouse_x, mouse_y = event.scenePos().x(), event.scenePos().y()
|
||||||
self.setPos(QPointF(mouse_x, mouse_y))
|
self.setPos(round_position(QPointF(mouse_x, mouse_y)))
|
||||||
self.point_dragged.emit(self)
|
self.point_dragged.emit(self)
|
||||||
|
|
||||||
def paint(self, painter, styles, widget=None):
|
def paint(self, painter, styles, widget=None):
|
||||||
pen1 = QPen(Qt.SolidLine)
|
pen1 = QPen(Qt.SolidLine)
|
||||||
pen1.setColor(QColor(128, 128, 128))
|
pen1.setColor(self.color)
|
||||||
painter.setPen(pen1)
|
painter.setPen(pen1)
|
||||||
|
|
||||||
brush1 = QBrush(Qt.SolidPattern)
|
brush1 = QBrush(Qt.SolidPattern)
|
||||||
@ -231,8 +335,7 @@ class CustomCenterPoint(QGraphicsObject):
|
|||||||
painter.drawRoundedRect(self.boundingRect(), 10, 10)
|
painter.drawRoundedRect(self.boundingRect(), 10, 10)
|
||||||
|
|
||||||
def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None:
|
def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None:
|
||||||
self.color = COLOR_HOVER_PORT
|
self.color = COLOR_HOVER_MID_POINT
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None:
|
def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None:
|
||||||
@ -261,6 +364,9 @@ class CustomCenterPoint(QGraphicsObject):
|
|||||||
painter.drawRoundedRect(self.boundingRect(), 10, 10) # 绘制函数
|
painter.drawRoundedRect(self.boundingRect(), 10, 10) # 绘制函数
|
||||||
painter.end()
|
painter.end()
|
||||||
|
|
||||||
|
def mouseDoubleClickEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
|
||||||
|
self.line.remove_mid_point(self)
|
||||||
|
|
||||||
|
|
||||||
class CustomPort(QGraphicsObject):
|
class CustomPort(QGraphicsObject):
|
||||||
port_clicked = pyqtSignal(QGraphicsObject)
|
port_clicked = pyqtSignal(QGraphicsObject)
|
||||||
@ -273,6 +379,8 @@ class CustomPort(QGraphicsObject):
|
|||||||
self.id = port_id
|
self.id = port_id
|
||||||
self.size = (10, 10)
|
self.size = (10, 10)
|
||||||
self.content = content
|
self.content = content
|
||||||
|
self.connected_lines = []
|
||||||
|
self.canvas = None
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
return QRectF(0, 0, self.size[0], self.size[1])
|
return QRectF(0, 0, self.size[0], self.size[1])
|
||||||
@ -328,6 +436,11 @@ class CustomPort(QGraphicsObject):
|
|||||||
pos = self.pos()
|
pos = self.pos()
|
||||||
return pos.x(), pos.y()
|
return pos.x(), pos.y()
|
||||||
|
|
||||||
|
def on_delete(self):
|
||||||
|
for line in self.connected_lines:
|
||||||
|
line.on_delete()
|
||||||
|
self.canvas.removeItem(self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return super(CustomPort, self).__repr__() + 'id = ' + str(self.id)
|
return super(CustomPort, self).__repr__() + 'id = ' + str(self.id)
|
||||||
|
|
||||||
@ -342,8 +455,6 @@ class CustomRect(QGraphicsItem):
|
|||||||
self.color = COLOR_NORMAL
|
self.color = COLOR_NORMAL
|
||||||
self.node = node
|
self.node = node
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
return QRectF(0, 0, 200, 50)
|
return QRectF(0, 0, 200, 50)
|
||||||
|
|
||||||
@ -372,7 +483,9 @@ class CustomRect(QGraphicsItem):
|
|||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
|
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
|
||||||
self.setPos(event.scenePos().x() - self.relative_pos[0], event.scenePos().y() - self.relative_pos[1])
|
self.setPos(round_position(
|
||||||
|
QPointF(event.scenePos().x() - self.relative_pos[0],
|
||||||
|
event.scenePos().y() - self.relative_pos[1])))
|
||||||
self.node.refresh_pos()
|
self.node.refresh_pos()
|
||||||
|
|
||||||
def mousePressEvent(self, evt: QGraphicsSceneMouseEvent):
|
def mousePressEvent(self, evt: QGraphicsSceneMouseEvent):
|
||||||
@ -385,7 +498,7 @@ class CustomRect(QGraphicsItem):
|
|||||||
print(self.relative_pos)
|
print(self.relative_pos)
|
||||||
if not evt.modifiers() == Qt.ControlModifier:
|
if not evt.modifiers() == Qt.ControlModifier:
|
||||||
self.scene().signal_clear_selection.emit()
|
self.scene().signal_clear_selection.emit()
|
||||||
self.setSelected(True)
|
self.scene().select_item(self)
|
||||||
print(self.scene().selectedItems())
|
print(self.scene().selectedItems())
|
||||||
self.color = COLOR_SELECTED
|
self.color = COLOR_SELECTED
|
||||||
elif evt.button() == Qt.RightButton:
|
elif evt.button() == Qt.RightButton:
|
||||||
@ -408,4 +521,8 @@ class CustomRect(QGraphicsItem):
|
|||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
self.color = COLOR_NORMAL
|
self.color = COLOR_NORMAL
|
||||||
self.setSelected(False)
|
self.scene().unselect_item(self)
|
||||||
|
|
||||||
|
def on_delete(self):
|
||||||
|
self.node.on_delete()
|
||||||
|
pass
|
||||||
|
@ -2,11 +2,12 @@ import sys
|
|||||||
from typing import Tuple, List, Dict
|
from typing import Tuple, List, Dict
|
||||||
import json
|
import json
|
||||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QToolButton, QSpacerItem, QSizePolicy, QGraphicsView, \
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QToolButton, QSpacerItem, QSizePolicy, QGraphicsView, \
|
||||||
QFrame, QApplication, QGraphicsScene, QGraphicsSceneMouseEvent
|
QFrame, QApplication, QGraphicsScene, QGraphicsSceneMouseEvent, QMenu, QGraphicsSceneContextMenuEvent, \
|
||||||
from PyQt5.QtCore import QSize, QCoreApplication, pyqtSignal, QLineF, QObject
|
QGraphicsTextItem
|
||||||
from PyQt5.QtGui import QIcon, QPixmap, QPen, QColor
|
from PyQt5.QtCore import QSize, QCoreApplication, pyqtSignal, QLineF, QObject, QPoint, Qt, QPointF
|
||||||
|
from PyQt5.QtGui import QIcon, QPixmap, QPen, QColor, QKeyEvent
|
||||||
|
|
||||||
from pmgwidgets.flowchart.flow_items import CustomRect, CustomPort, CustomLine, CustomCenterPoint
|
from pmgwidgets.flowchart.flow_items import CustomRect, CustomPort, CustomLine, CustomMidPoint
|
||||||
|
|
||||||
COLOR_NORMAL = QColor(212, 227, 242)
|
COLOR_NORMAL = QColor(212, 227, 242)
|
||||||
COLOR_HOVER = QColor(255, 200, 00)
|
COLOR_HOVER = QColor(255, 200, 00)
|
||||||
@ -18,16 +19,30 @@ class PMGraphicsScene(QGraphicsScene):
|
|||||||
signal_port_clicked = pyqtSignal(str) # 点击端口的事件
|
signal_port_clicked = pyqtSignal(str) # 点击端口的事件
|
||||||
signal_clear_selection = pyqtSignal() # 清除选择的事件
|
signal_clear_selection = pyqtSignal() # 清除选择的事件
|
||||||
|
|
||||||
def __init__(self, parent=None, graphics_view: 'QGraphicsView' = None):
|
def __init__(self, parent=None, graphics_view: 'QGraphicsView' = None, flow_widget: 'PMFlowWidget' = None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
from pmgwidgets.flowchart.flow_items import CustomLine
|
from pmgwidgets.flowchart.flow_items import CustomLine
|
||||||
self.lines: List[CustomLine] = []
|
self.lines: List[CustomLine] = []
|
||||||
|
self.nodes: List['Node'] = []
|
||||||
self.drawing_lines = False
|
self.drawing_lines = False
|
||||||
self.line_start_port = None
|
self.line_start_port = None
|
||||||
self.line_start_point = None
|
self.line_start_point = None
|
||||||
self.line_end_port = None
|
self.line_end_port = None
|
||||||
self.line = self.addLine(0, 0, 100, 100, QPen())
|
self.line = self.addLine(0, 0, 1, 1, QPen())
|
||||||
self.graphics_view = graphics_view
|
self.graphics_view = graphics_view
|
||||||
|
self.flow_widget: 'PMFlowWidget' = flow_widget
|
||||||
|
self.menu = QMenu()
|
||||||
|
self.menu.addAction('New').triggered.connect(lambda x: self.add_node())
|
||||||
|
self.menu.addAction('Delete Selected').triggered.connect(lambda x: self.delete_selected_item())
|
||||||
|
self.selected_items = []
|
||||||
|
|
||||||
|
def contextMenuEvent(self, event: 'QGraphicsSceneContextMenuEvent') -> None:
|
||||||
|
super(PMGraphicsScene, self).contextMenuEvent(event)
|
||||||
|
self.menu.exec_(event.screenPos())
|
||||||
|
|
||||||
|
def keyPressEvent(self, event: 'QKeyEvent') -> None:
|
||||||
|
if event.key() == Qt.Key_Delete:
|
||||||
|
self.delete_selected_item()
|
||||||
|
|
||||||
def mouseMoveEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
|
def mouseMoveEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
|
||||||
super(PMGraphicsScene, self).mouseMoveEvent(event)
|
super(PMGraphicsScene, self).mouseMoveEvent(event)
|
||||||
@ -46,18 +61,51 @@ class PMGraphicsScene(QGraphicsScene):
|
|||||||
self.signal_item_dragged.connect(line.refresh)
|
self.signal_item_dragged.connect(line.refresh)
|
||||||
self.drawing_lines = False
|
self.drawing_lines = False
|
||||||
|
|
||||||
# def selectionChanged(self) -> None:
|
def add_node(self):
|
||||||
# super(PMGraphicsScene, self).selectionChanged()
|
view = self.graphics_view
|
||||||
# print('selection changed !')
|
|
||||||
|
n = Node(self, 'node3', input_ports=[CustomPort(10), CustomPort(11)],
|
||||||
|
output_ports=[CustomPort(12), CustomPort(13), CustomPort(14)])
|
||||||
|
n.set_pos(200, 50)
|
||||||
|
print(n.get_pos())
|
||||||
|
self.nodes.append(n)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_selected_item(self):
|
||||||
|
'''
|
||||||
|
删除被选中的物品
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
print(self.selectedItems())
|
||||||
|
for selected_item in self.selected_items:
|
||||||
|
if hasattr(selected_item, 'on_delete'):
|
||||||
|
selected_item.on_delete()
|
||||||
|
self.selected_items = []
|
||||||
|
print('delete!')
|
||||||
|
|
||||||
|
def unselect_item(self, item):
|
||||||
|
if item in self.selected_items:
|
||||||
|
self.selected_items.remove(item)
|
||||||
|
|
||||||
|
def select_item(self, item):
|
||||||
|
if item not in self.selected_items:
|
||||||
|
self.selected_items.append(item)
|
||||||
|
|
||||||
|
|
||||||
class Node(QObject):
|
class Node(QObject):
|
||||||
|
'''
|
||||||
|
Node是一个节点的抽象
|
||||||
|
'''
|
||||||
|
|
||||||
def __init__(self, canvas: 'PMGraphicsScene', name, input_ports: List[CustomPort] = None,
|
def __init__(self, canvas: 'PMGraphicsScene', name, input_ports: List[CustomPort] = None,
|
||||||
output_ports: List[CustomPort] = None):
|
output_ports: List[CustomPort] = None, content: object = None):
|
||||||
super(Node, self).__init__()
|
super(Node, self).__init__()
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.base_rect = CustomRect(self)
|
self.base_rect = CustomRect(self)
|
||||||
|
self.text = QGraphicsTextItem(parent=self.base_rect)
|
||||||
|
self.text.setPos(100, 10)
|
||||||
|
self.text.setPlainText(self.name)
|
||||||
if input_ports == None:
|
if input_ports == None:
|
||||||
self.input_ports = [CustomPort(0), CustomPort(1)]
|
self.input_ports = [CustomPort(0), CustomPort(1)]
|
||||||
else:
|
else:
|
||||||
@ -67,13 +115,25 @@ class Node(QObject):
|
|||||||
else:
|
else:
|
||||||
self.output_ports = output_ports
|
self.output_ports = output_ports
|
||||||
self.canvas = canvas
|
self.canvas = canvas
|
||||||
|
self.content = None
|
||||||
|
|
||||||
self.setup()
|
self.setup()
|
||||||
|
|
||||||
def set_pos(self, x: int, y: int):
|
def set_pos(self, x: int, y: int):
|
||||||
|
'''
|
||||||
|
设置位置,左上角角点
|
||||||
|
:param x:
|
||||||
|
:param y:
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
self.base_rect.setPos(x, y)
|
self.base_rect.setPos(x, y)
|
||||||
self.refresh_pos()
|
self.refresh_pos()
|
||||||
|
|
||||||
def get_pos(self) -> Tuple[int, int]:
|
def get_pos(self) -> Tuple[int, int]:
|
||||||
|
'''
|
||||||
|
获取位置,左上角角点
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
pos = self.base_rect.pos()
|
pos = self.base_rect.pos()
|
||||||
return pos.x(), pos.y()
|
return pos.x(), pos.y()
|
||||||
|
|
||||||
@ -84,15 +144,16 @@ class Node(QObject):
|
|||||||
x_input = self.base_rect.x() + 5
|
x_input = self.base_rect.x() + 5
|
||||||
x_output = self.base_rect.x() + self.base_rect.boundingRect().width() - 15
|
x_output = self.base_rect.x() + self.base_rect.boundingRect().width() - 15
|
||||||
for i, p in enumerate(self.input_ports):
|
for i, p in enumerate(self.input_ports):
|
||||||
p.setPos(x_input, y + int(dy_input * (1 + i)))
|
p.setPos(QPointF(x_input, y + int(dy_input * (1 + i))))
|
||||||
for i, p in enumerate(self.output_ports):
|
for i, p in enumerate(self.output_ports):
|
||||||
p.setPos(x_output, y + int(dy_output * (1 + i)))
|
p.setPos(QPointF(x_output, y + int(dy_output * (1 + i))))
|
||||||
self.canvas.signal_item_dragged.emit('')
|
self.canvas.signal_item_dragged.emit('')
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.base_rect.setPos(80, 80)
|
self.base_rect.setPos(80, 80)
|
||||||
self.canvas.signal_clear_selection.connect(self.base_rect.on_clear_selection)
|
self.canvas.signal_clear_selection.connect(self.base_rect.on_clear_selection)
|
||||||
self.canvas.addItem(self.base_rect)
|
self.canvas.addItem(self.base_rect)
|
||||||
|
|
||||||
for p in self.input_ports + self.output_ports:
|
for p in self.input_ports + self.output_ports:
|
||||||
self.canvas.addItem(p)
|
self.canvas.addItem(p)
|
||||||
p.port_clicked.connect(self.on_port_clicked)
|
p.port_clicked.connect(self.on_port_clicked)
|
||||||
@ -109,6 +170,14 @@ class Node(QObject):
|
|||||||
self.canvas.line_start_point = port.center_pos
|
self.canvas.line_start_point = port.center_pos
|
||||||
self.canvas.line_start_port = port
|
self.canvas.line_start_port = port
|
||||||
|
|
||||||
|
def on_delete(self):
|
||||||
|
for port in self.input_ports + self.output_ports:
|
||||||
|
port.canvas = self.canvas
|
||||||
|
port.on_delete()
|
||||||
|
self.canvas.removeItem(self.base_rect)
|
||||||
|
self.canvas.nodes.remove(self)
|
||||||
|
self.deleteLater()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
s = super(Node, self).__repr__()
|
s = super(Node, self).__repr__()
|
||||||
return s + repr(self.input_ports) + repr(self.output_ports)
|
return s + repr(self.input_ports) + repr(self.output_ports)
|
||||||
@ -274,7 +343,7 @@ class PMFlowWidget(QWidget):
|
|||||||
# self.rect2 = CustomRect()
|
# self.rect2 = CustomRect()
|
||||||
# self.rect2.setPos(100, 100)
|
# self.rect2.setPos(100, 100)
|
||||||
#
|
#
|
||||||
self.scene = PMGraphicsScene(graphics_view=self.graphicsView)
|
self.scene = PMGraphicsScene(graphics_view=self.graphicsView, flow_widget=self)
|
||||||
self.scene.setSceneRect(0, 0, 300, 300)
|
self.scene.setSceneRect(0, 0, 300, 300)
|
||||||
|
|
||||||
# self.scene.addItem(self.rect)
|
# self.scene.addItem(self.rect)
|
||||||
@ -294,7 +363,7 @@ class PMFlowWidget(QWidget):
|
|||||||
|
|
||||||
self.nodes = [self.n, self.n2]
|
self.nodes = [self.n, self.n2]
|
||||||
|
|
||||||
self.nodes: List[Node] = []
|
self.nodes: List[Node] = self.scene.nodes
|
||||||
self.lines = self.scene.lines
|
self.lines = self.scene.lines
|
||||||
|
|
||||||
self.load_flowchart()
|
self.load_flowchart()
|
||||||
@ -342,8 +411,6 @@ class PMFlowWidget(QWidget):
|
|||||||
node_properties['input_ports'] = input_ports_dic
|
node_properties['input_ports'] = input_ports_dic
|
||||||
node_properties['output_ports'] = output_ports_dic
|
node_properties['output_ports'] = output_ports_dic
|
||||||
nodes_dic[node.name] = node_properties
|
nodes_dic[node.name] = node_properties
|
||||||
# print(nodes_dic)
|
|
||||||
|
|
||||||
with open(r'c:\users\12957\desktop\123.txt', 'w') as f:
|
with open(r'c:\users\12957\desktop\123.txt', 'w') as f:
|
||||||
json.dump(fc_info, f, indent=4)
|
json.dump(fc_info, f, indent=4)
|
||||||
pass
|
pass
|
||||||
@ -380,7 +447,7 @@ class PMFlowWidget(QWidget):
|
|||||||
mid_positions = line_property['mid_positions']
|
mid_positions = line_property['mid_positions']
|
||||||
mid_points = []
|
mid_points = []
|
||||||
for pos in mid_positions:
|
for pos in mid_positions:
|
||||||
mid_points.append(CustomCenterPoint(pos=pos))
|
mid_points.append(CustomMidPoint(pos=QPointF(*pos)))
|
||||||
print(start_port, end_port, start_id, end_id)
|
print(start_port, end_port, start_id, end_id)
|
||||||
|
|
||||||
line = CustomLine(canvas=self.scene, start_port=start_port, end_port=end_port, mid_points=mid_points)
|
line = CustomLine(canvas=self.scene, start_port=start_port, end_port=end_port, mid_points=mid_points)
|
||||||
|
7
pmgwidgets/flowchart/utils.py
Normal file
7
pmgwidgets/flowchart/utils.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from PyQt5.QtCore import QPointF
|
||||||
|
|
||||||
|
|
||||||
|
def round_position(point: QPointF, pixels=5):
|
||||||
|
x, y = point.x(), point.y()
|
||||||
|
x_cor, y_cor = round(x * 1.0 / pixels) * pixels, round(y * 1.0 / pixels) * pixels
|
||||||
|
return QPointF(x_cor, y_cor)
|
@ -12,6 +12,9 @@ class Extension(BaseExtension):
|
|||||||
app_toolbar_interface = self.extension_lib.get_interface('applications_toolbar')
|
app_toolbar_interface = self.extension_lib.get_interface('applications_toolbar')
|
||||||
import os
|
import os
|
||||||
path = os.path.dirname(__file__)
|
path = os.path.dirname(__file__)
|
||||||
|
app_toolbar_interface.add_app( group='应用测试', text='测试插件',
|
||||||
|
icon_path=':/pyqt/source/images/lc_searchdialog.png', callback=lambda :print('this is app'), hint='')
|
||||||
|
|
||||||
app_toolbar_interface.add_process_action('应用测试', '测试对话框',
|
app_toolbar_interface.add_process_action('应用测试', '测试对话框',
|
||||||
':/pyqt/source/images/lc_searchdialog.png',
|
':/pyqt/source/images/lc_searchdialog.png',
|
||||||
['python','-u',os.path.join(path,'run_dialog.py')])
|
['python','-u',os.path.join(path,'run_dialog.py')])
|
||||||
|
Loading…
Reference in New Issue
Block a user