PDA

View Full Version : Node connections [PySide]



iRex
24th August 2017, 19:24
Hello everyone! This is my first post here. Using search I found that here, one can post PyQt questions but I'm using PySide. I don't know If I'm breaking the rules of this forum. If so I ask moderators to remove this post.
I'm very new in programming and never used C++ but writing this code my guide was QT documentation because it is more descriptive than PyQt.
What I'm looking for is to create node graph kind of UI. I have realized nodes and connections. It works fine with two items connected in the scene but when I create two more nodes it does not work properly. I mean if you create two nodes with double click, then select them and do right click you'll see a path between this two nodes. If you move one of the node the pathElements will follow the nodes. Now add two more nodes and connect them. You'll see that newly created path does not transform.
Double click = creates nodes. Selecting 2 nodes and right click creates path item between 2 selected items.
Here is the code:


from PySide.QtCore import *
from PySide.QtGui import *

rad = 5

class WindowClass(QMainWindow):
def __init__(self):
super(WindowClass, self).__init__()
self.view = ViewClass()
self.setCentralWidget(self.view)


class ViewClass(QGraphicsView):
def __init__(self):
super(ViewClass, self).__init__()

self.setDragMode(QGraphicsView.RubberBandDrag)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwa ysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlways Off)

self.s = SceneClass()
self.setScene(self.s)
self.setRenderHint(QPainter.Antialiasing)


class SceneClass(QGraphicsScene):
def __init__(self, id=None):
super(SceneClass, self).__init__()
self.setSceneRect(-1000, -1000, 2000, 2000)
self.grid = 30
self.it = None
self.node = None

def drawBackground(self, painter, rect):
if False:
painter = QPainter()
rect = QRect()

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 addNode(self, pos=False):
if not pos:
pos = QPoint(0, 0)
item = ItemClass(self.grid, len(self.items()))
self.addItem(item)
item.setPos(pos)


def mouseDoubleClickEvent(self, event):
self.addNode(event.scenePos())
super(SceneClass, self).mouseDoubleClickEvent(event)


def mousePressEvent(self, event):
if event.button() == Qt.RightButton:
self._start = event.scenePos()
#####
path = QPainterPath()
path.moveTo(self.selectedItems()[0].pos().x(), self.selectedItems()[0].pos().y())
path.lineTo(self.selectedItems()[1].pos().x(), self.selectedItems()[1].pos().y())
item = Path(path, self)

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

self.addItem(item)

super(SceneClass, self).mousePressEvent(event)


class Path(QGraphicsPathItem):
def __init__(self, path, scene):
super(Path, self).__init__(path)
self.setPen(QPen(Qt.red, 1.75))

def updateElement(self, index, pos):
path = self.path()
path.setElementPositionAt(index, pos.x(), pos.y())
self.setPath(path)


class ItemClass(QGraphicsItem):
def __init__(self, height, index ):
super(ItemClass, self).__init__()
self.x = 0
self.y = 0
self.w = 150
self.h = height
self.hover = None
self.setAcceptHoverEvents(True)
self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
self.setFlag(QGraphicsItem.ItemSendsGeometryChange s)

self.linkToItem = None

self.index = index
self.setZValue(1)

def itemChange(self, change, value):

if change == QGraphicsItem.ItemPositionChange:
if self.linkToItem:
self.linkToItem.updateElement(self.index, value)

return QGraphicsItem.itemChange(self, change, value)

def boundingRect(self):
return QRect(self.x, self.y, self.w, self.h)

def paint(self, painter, opt, w):
rec = self.boundingRect()
if False:
painter = QPainter()
if not self.hover:
color = Qt.darkGray
else:
color = Qt.gray
if self.isSelected():
color = Qt.yellow


painter.fillRect(rec.adjusted(3,3,-3,-3),color)

self.scene().update()


if __name__ == '__main__':
app = QApplication([])
wd = WindowClass()
wd.show()
app.exec_()

wysota
28th August 2017, 13:22
This code is incorrect:


def updateElement(self, index, pos):
path = self.path()
path.setElementPositionAt(index, pos.x(), pos.y())
self.setPath(path)

For this to work index should always be 0 or 1 but each item you create gets an increasing value of index (so that the second pair of rectangles has indices 2 and 3).

In my opinion the code should be different - each line should have references to two end point items. Then you can compare which end point item you are moving and update the proper point.

Alternatively each ItemClass instance can store a list of edges connected to it (assuming there can be more than one) and each time the item is moved, update each edge in the list.