Trying to create nodes and connect them to each other. I'm stacked on setElementPositionAt
. The error is:
AttributeError: 'PySide.QtGui.QPainterPath' object has no attribute 'updateElement'
I have found the working code here: How can I draw nodes and edges in PyQT? but can't adapt it to my widget.
What I'm doing wrong?
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.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
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.p = QPainterPath()
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 mousePressEvent(self, event):
if event.button() == Qt.RightButton:
self.p.moveTo(0, 0)
self.p.lineTo(200, 100)
self.it = Path(self.p,None)
self.addItem(self.it)
for i in xrange(2):
self.node = Node(self, i, QPointF(self.p.elementAt(i)))
self.node.setPos(QPointF(self.p.elementAt(i)))
self.addItem(self.node)
super(SceneClass, self).mousePressEvent(event)
class Path(QGraphicsPathItem):
def __init__(self, path, scene):
super(Path, self).__init__(path)
self.pth = path
self.scn = SceneClass(self.setPen(QPen(Qt.red, 1.75)))
def updateElement(self, index, pos):
print pos
self.pth.setElementPositionAt(index, pos.x(), pos.y())
self.pth.setPath(self)
class Node(QGraphicsEllipseItem):
def __init__(self, path, index, pos):
super(Node, self).__init__(-rad, -rad, 2*rad, 2*rad)
self.pos = pos
self.rad = rad
self.path = QPainterPath()
self.index = index
self.setZValue(1)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
self.setBrush(Qt.green)
def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionChange:
self.path.updateElement(self.index, value)
return QGraphicsEllipseItem.itemChange(self, change, value)
if __name__ == '__main__':
app = QApplication([])
wd = WindowClass()
wd.show()
app.exec_()
You have made changes to the base classes that you have taken as reference so it is normal for you to have errors if you do not understand the code.
When you call the updateElement
method you must do it from an instance of the Path class, not an instance of the class QPaintePath
, I have placed the same code of the author that you took as a reference initially and I have added to your graphic part.
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.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
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 mousePressEvent(self, event):
if event.button() == Qt.RightButton:
path = QPainterPath()
path.moveTo(0, 0)
path.lineTo(200, 100)
self.addItem(Path(path, self))
super(SceneClass, self).mousePressEvent(event)
class Node(QGraphicsEllipseItem):
def __init__(self, path, index):
super(Node, self).__init__(-rad, -rad, 2*rad, 2*rad)
self.rad = rad
self.path = path
self.index = index
self.setZValue(1)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
self.setBrush(Qt.green)
def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionChange:
self.path.updateElement(self.index, value)
return QGraphicsEllipseItem.itemChange(self, change, value)
class Path(QGraphicsPathItem):
def __init__(self, path, scene):
super(Path, self).__init__(path)
for i in range(path.elementCount()):
node = Node(self, i)
node.setPos(QPointF(path.elementAt(i)))
scene.addItem(node)
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)