Search code examples
pythonpyqtpyqt4qpainterpathqgraphicspathitem

how can I move the points in a Qt QPainterPath after creation?


I created a QGraphicsPathItem by passing the constructor a QPainterPath with about 10 QPoint's in it. Now how can I move the points in the path around?

For example:

This to create a box:

path = QtGui.QPainterPath()
path.moveTo(0, 0)
path.lineTo(10, 0)
path.lineTo(10, 10)
path.lineTo(0, 10)

line = QtGui.QGraphicsPathItem()
line.setPath(path)

Now after some time goes by I want to make this box wider by grabbing the top & bottom right points and moving them right. How can I access the points? The Qt documentation for QPainterPath indicates that path.elementAt(i) is the way to access data within the path, but that returns a QElementObject and I could not find much documentation for an "element object", and it is definitely not a QPointF (which is what I would expect to get...right?). So how can I get a QPointF out of this element? And once I do get the points, is it fine to just call their QPointF.setX() and QPointF.setY() and the line will re-draw, or do I need to re-set it to the QGraphicsPathItem with a new call to line.setPath()?

As a note this is PyQt4, python 2.7. However I'll take a C++ answer if you have it, though I don't know C++ at all it seems pretty easy to translate.


Solution

  • you can get the coordinates through path.elementAt(i).x, path.elementAt(i).y, and set new values ​​using the path.setElementPositionAt() method.

    In the next section I show an example.

    import sys
    
    import random
    
    from PyQt4 import QtGui, QtCore
    
    def movePoints():
        p = line.path()
        for i in range(p.elementCount()):
            xo, yo = p.elementAt(i).x, p.elementAt(i).y
            xn, yn = (e+10*(random.random()-0.5) for e in  (xo, yo))
            p.setElementPositionAt(i, xn, yn)
        line.setPath(p)
    
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        w = QtGui.QGraphicsView()
        scene = QtGui.QGraphicsScene(w)
        w.setScene(scene)
        timer = QtCore.QTimer()
        timer.timeout.connect(movePoints)
    
        path = QtGui.QPainterPath()
        path.moveTo(0, 0)
        path.lineTo(10, 0)
        path.lineTo(10, 10)
        path.lineTo(0, 10)
    
        line = QtGui.QGraphicsPathItem()
        line.setPath(path)
        scene.addItem(line)
        timer.start(1000)
        w.show()
        sys.exit(app.exec_())
    

    If you want to use QPointF , the code equivalent to the example is the following:

    def movePoints():
        p = line.path()
        for i in range(p.elementCount()):
            point = QtCore.QPointF(p.elementAt(i))
            point += QtCore.QPointF(10*random.random()-5, 10*random.random()-5)
            p.setElementPositionAt(i, point.x(), point.y())
        line.setPath(p)