【问题标题】:Make GraphicsItems editable by mouse action and mouse events in a Graphicscene通过图形场景中的鼠标动作和鼠标事件使图形项可编辑
【发布时间】:2020-08-31 21:10:45
【问题描述】:

我目前正在编写一个交互式 GUI,下面的代码通过鼠标事件以连续的方式插入节点和各自的边,通过双击事件开始和结束绘制会话(基于这篇文章 Join QGraphicsItem and QPainter in same GraphicsScene)。我想让节点和边缘可编辑,因为在绘制后用户可以通过鼠标事件在节点位置周围移动,如下例所示。 how to use QGraphicsView::RubberBandDrag?,

代码

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
        self.pos = None
        self.pos_end = None
        self.node_start = None
        self.node_end = None

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            "Agregar Nodo"
            self.node_start = Node()
            self.node_start.setPos(event.scenePos())
            self.addItem(self.node_start)
            "Agregar Edge"
            self._edge_item = Edge()
            self._edge_item.src = self.node_start
            self.addItem(self._edge_item)
            if self.node_end:
                self.node_end = None
                self.node_start = None

            self.node_end = self.node_start

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton and self.node_end:
            "Agregar Nodo"
            self.node_start = Node()
            self.node_start.setPos(event.scenePos())
            self.addItem(self.node_start)
            self.node_end = self.node_start
            "Agregar Edge"
            self._edge_item = Edge()
            self._edge_item.src = self.node_start
            self.addItem(self._edge_item)

    def mouseMoveEvent(self, event):
        if self._edge_item and self.node_end:
            self._edge_item.p1 = 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()

我尝试通过在边缘类中添加一个悬停事件来启动,但是在设置为接受悬停事件并创建一个函数来指示对该事件执行操作后,该函数不会触发。

【问题讨论】:

    标签: python pyqt pyqt5 qgraphicsview


    【解决方案1】:

    OP 的逻辑不正确,所以我不得不稍微修改一下,使其正确地遵循顺序。

    另一方面,移动项目的行为已经默认实现,但鼠标事件必须发送到项目,为此需要调用 mouseXEvent 方法的 super() 方法。

    class SceneClass(QGraphicsScene):
        def __init__(self, parent=None):
            super(SceneClass, self).__init__(QRectF(-1000, -1000, 2000, 2000), parent)
            self._edge_item = None
            self._last_node = None
    
        def mouseDoubleClickEvent(self, event):
            if event.button() == Qt.LeftButton:
                if self._last_node:
                    self._last_node = None
                    self._edge_item = None
                else:
                    node = Node()
                    node.setPos(event.scenePos())
                    self.addItem(node)
                    self._edge_item = Edge()
                    self._edge_item.src = node
                    self.addItem(self._edge_item)
                    self._last_node = node
                return
            super(SceneClass, self).mouseDoubleClickEvent(event)
    
        def mousePressEvent(self, event):
            if event.button() == Qt.LeftButton and self._last_node:
    
                node = Node()
                node.setPos(event.scenePos())
                self.addItem(node)
                self._edge_item.dst = node
    
                self._edge_item = Edge()
                self._edge_item.src = node
                self.addItem(self._edge_item)
    
                self._last_node = node
                return
            super(SceneClass, self).mousePressEvent(event)
    
        def mouseMoveEvent(self, event):
            if self._edge_item:
                self._edge_item.p1 = 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()
    

    【讨论】:

    • 感谢您的快速响应,我是pyqt的新手,所以我会修改我的代码,看看您更正的原因,这真的很有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    • 2018-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多