1

The purpose of this code is node graph kind of UI. Double click creates rectangles and right click connects them with line. If you move on of the rectangle the corresponding end of line moves with it. The problem is that the line moves only with first two rectangles. If you create another pair of rectangles and connect them with line it stops moving. I have started to learn PySide/PyQt recently so maybe I don't understand all code.

Here is the code: https://github.com/cyberiRex/irex/blob/master/nodeGraph

Cyberikia
  • 91
  • 6
  • Although it lacks verifications to your code this works, I obtain the following having certain provisions like adding the following `if event.button() == Qt.RightButton: if len(self.selectedItems()) == 2:`.In the end I get the following: http://imgur.com/a/TtEeQ – eyllanesc Sep 10 '17 at 16:58
  • Yes, but curve does not updates. – Cyberikia Sep 10 '17 at 17:24
  • To what curve do you mean, to the red line ?, explain yourself better please. – eyllanesc Sep 10 '17 at 17:26
  • You want the red lines to move when the rectangles move? – eyllanesc Sep 10 '17 at 17:29
  • Yes. Actually, the line moves but only if there are only two rectangles in the scene. If you create another pair of rectangles and connect them with red line it does not moves. – Cyberikia Sep 10 '17 at 18:03
  • 1
    I just understand, please [edit](https://stackoverflow.com/posts/46142167/edit) and improve the explanation of your question – eyllanesc Sep 10 '17 at 18:05

1 Answers1

1

The Code that generates this error is the following one:

self.selectedItems()[0].linkToItem = item
self.selectedItems()[1].linkToItem = item

Let's say that one node is already connected to another by a link, when another link is added, the previous link is removed, which is why they are disconnected.

The logic like this will continue generating similar errors so the solution I propose is a new solution logic, for this I base on the following example Elastic Nodes Example. From what you can take as a basis to understand the logic of my solution, obviously I have made some variants to meet your requirements.

In a first part I have replaced the base classes to QGraphicsRectItem and QGraphicsLineItem to reduce implementation. The logic is based on giving each Edge 2 Node to which they connect so that when it is updated take as reference to the nodes. in addition each node stores a list of the edges so that it executes the update every time the node is moved. The following code implements the above:

class SceneClass(QGraphicsScene):
    grid = 30

    def __init__(self, parent=None):
        QGraphicsScene.__init__(self, QRectF(-1000, -1000, 2000, 2000), parent)

    def drawBackground(self, painter, rect):
        painter.fillRect(rect, QColor(30, 30, 30))
        left = int(rect.left()) - int((rect.left()) % self.grid)
        top = int(rect.top()) - int((rect.top()) % self.grid)
        right = int(rect.right())
        bottom = int(rect.bottom())
        lines = []
        for x in range(left, right, self.grid):
            lines.append(QLine(x, top, x, bottom))
        for y in range(top, bottom, self.grid):
            lines.append(QLine(left, y, right, y))
        painter.setPen(QPen(QColor(50, 50, 50)))
        painter.drawLines(lines)

    def mouseDoubleClickEvent(self, event):
        node = Node()
        self.addItem(node)
        node.setPos(event.scenePos())
        QGraphicsScene.mouseMoveEvent(self, event)

    def mousePressEvent(self, event):
        if event.button() == Qt.RightButton:
            if len(self.selectedItems()) == 2:
                edge = Edge(self.selectedItems()[0], self.selectedItems()[1])
                self.addItem(edge)
        QGraphicsScene.mousePressEvent(self, event)


class Node(QGraphicsRectItem):
    def __init__(self, rect=QRectF(-75, -15, 150, 30), parent=None):
        QGraphicsRectItem.__init__(self, rect, parent)
        self.edges = []
        self.setZValue(1)
        self.setBrush(Qt.darkGray)
        self.setFlags(QGraphicsItem.ItemIsMovable |
                      QGraphicsItem.ItemIsSelectable |
                      QGraphicsItem.ItemSendsGeometryChanges)

    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, 1.75))
        self.adjust()

    def adjust(self):
        self.prepareGeometryChange()
        self.setLine(QLineF(self.dest.pos(), self.source.pos()))

Obtaining what is shown in the following image:

enter image description here

The complete example can be found in the following link

eyllanesc
  • 235,170
  • 19
  • 170
  • 241