172 lines
5.1 KiB
Python
172 lines
5.1 KiB
Python
"""
|
|
图形化编辑器控件
|
|
用于可视化编辑映射图
|
|
"""
|
|
from PyQt5.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QGraphicsView, QGraphicsScene,
|
|
QGraphicsEllipseItem, QGraphicsLineItem, QGraphicsTextItem,
|
|
QPushButton, QToolBar, QAction
|
|
)
|
|
from PyQt5.QtCore import Qt, QPointF, QRectF, pyqtSignal
|
|
from PyQt5.QtGui import QPen, QBrush, QColor, QPainter
|
|
|
|
from models.mapping_graph import MappingGraph, GraphNode, GraphEdge
|
|
from config import Config
|
|
from utils.logger import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
class GraphNodeItem(QGraphicsEllipseItem):
|
|
"""图节点图形项"""
|
|
|
|
def __init__(self, node: GraphNode, x: float, y: float):
|
|
super().__init__(0, 0, Config.NODE_WIDTH, Config.NODE_HEIGHT)
|
|
|
|
self.node = node
|
|
self.setPos(x, y)
|
|
|
|
# 设置样式
|
|
self.setBrush(QBrush(QColor(33, 150, 243)))
|
|
self.setPen(QPen(QColor(25, 118, 210), 2))
|
|
|
|
# 可移动
|
|
self.setFlag(QGraphicsEllipseItem.ItemIsMovable)
|
|
self.setFlag(QGraphicsEllipseItem.ItemIsSelectable)
|
|
self.setFlag(QGraphicsEllipseItem.ItemSendsGeometryChanges)
|
|
|
|
# 添加文本标签
|
|
self.text_item = QGraphicsTextItem(self)
|
|
self.text_item.setPlainText(node.field.name)
|
|
self.text_item.setDefaultTextColor(Qt.white)
|
|
|
|
# 居中文本
|
|
text_rect = self.text_item.boundingRect()
|
|
text_x = (Config.NODE_WIDTH - text_rect.width()) / 2
|
|
text_y = (Config.NODE_HEIGHT - text_rect.height()) / 2
|
|
self.text_item.setPos(text_x, text_y)
|
|
|
|
def itemChange(self, change, value):
|
|
"""节点位置改变时的处理"""
|
|
if change == QGraphicsEllipseItem.ItemPositionChange:
|
|
# 更新连接的边
|
|
pass
|
|
|
|
return super().itemChange(change, value)
|
|
|
|
|
|
class GraphEdgeItem(QGraphicsLineItem):
|
|
"""图边图形项"""
|
|
|
|
def __init__(self, edge: GraphEdge, source_item: GraphNodeItem, target_item: GraphNodeItem):
|
|
super().__init__()
|
|
|
|
self.edge = edge
|
|
self.source_item = source_item
|
|
self.target_item = target_item
|
|
|
|
# 设置样式
|
|
self.setPen(QPen(QColor(100, 100, 100), Config.EDGE_WIDTH))
|
|
|
|
# 更新位置
|
|
self.update_position()
|
|
|
|
def update_position(self):
|
|
"""更新边的位置"""
|
|
source_center = self.source_item.sceneBoundingRect().center()
|
|
target_center = self.target_item.sceneBoundingRect().center()
|
|
|
|
self.setLine(
|
|
source_center.x(), source_center.y(),
|
|
target_center.x(), target_center.y()
|
|
)
|
|
|
|
|
|
class GraphViewWidget(QGraphicsView):
|
|
"""图形视图控件"""
|
|
|
|
node_selected = pyqtSignal(GraphNode)
|
|
edge_selected = pyqtSignal(GraphEdge)
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
# 创建场景
|
|
self.scene = QGraphicsScene()
|
|
self.setScene(self.scene)
|
|
|
|
# 设置视图属性
|
|
self.setRenderHint(QPainter.Antialiasing)
|
|
self.setDragMode(QGraphicsView.ScrollHandDrag)
|
|
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
|
|
|
|
# 存储图形项
|
|
self.node_items = {} # field_id -> GraphNodeItem
|
|
self.edge_items = {} # edge_id -> GraphEdgeItem
|
|
|
|
logger.info("Graph view widget initialized")
|
|
|
|
def load_graph(self, graph: MappingGraph):
|
|
"""加载映射图"""
|
|
self.scene.clear()
|
|
self.node_items.clear()
|
|
self.edge_items.clear()
|
|
|
|
# 添加节点
|
|
for field_id, node in graph.nodes.items():
|
|
self.add_node(node)
|
|
|
|
# 添加边
|
|
for edge in graph.edges:
|
|
self.add_edge(edge)
|
|
|
|
logger.info(f"Loaded graph: {len(graph.nodes)} nodes, {len(graph.edges)} edges")
|
|
|
|
def add_node(self, node: GraphNode):
|
|
"""添加节点"""
|
|
node_item = GraphNodeItem(node, node.x, node.y)
|
|
self.scene.addItem(node_item)
|
|
self.node_items[node.field.id] = node_item
|
|
|
|
def add_edge(self, edge: GraphEdge):
|
|
"""添加边"""
|
|
source_item = self.node_items.get(edge.source_field_id)
|
|
target_item = self.node_items.get(edge.target_field_id)
|
|
|
|
if source_item and target_item:
|
|
edge_item = GraphEdgeItem(edge, source_item, target_item)
|
|
self.scene.addItem(edge_item)
|
|
if edge.id:
|
|
self.edge_items[edge.id] = edge_item
|
|
|
|
def auto_layout(self):
|
|
"""自动布局(简单的圆形布局)"""
|
|
import math
|
|
|
|
nodes = list(self.node_items.values())
|
|
if not nodes:
|
|
return
|
|
|
|
center_x = 400
|
|
center_y = 300
|
|
radius = 200
|
|
|
|
angle_step = 2 * math.pi / len(nodes)
|
|
|
|
for i, node_item in enumerate(nodes):
|
|
angle = i * angle_step
|
|
x = center_x + radius * math.cos(angle)
|
|
y = center_y + radius * math.sin(angle)
|
|
node_item.setPos(x, y)
|
|
|
|
# 更新所有边
|
|
for edge_item in self.edge_items.values():
|
|
edge_item.update_position()
|
|
|
|
logger.info("Auto layout applied")
|
|
|
|
def wheelEvent(self, event):
|
|
"""鼠标滚轮缩放"""
|
|
factor = 1.2 if event.angleDelta().y() > 0 else 0.8
|
|
self.scale(factor, factor)
|