Search code examples
pythonrotationpyqt5qgraphicsviewqgraphicsitem

How do I animate a rotation in pyqt5?


How do I animate the rotation? In my case I have a angle which is a QVariant type. Reading the docs I saw that to animate some thing using the QVariantAnimation my variable have to be a QVariant type and in this case Float is. But my code is not running. I don't know if float was QVariant in the last version of Qt and It isn't more.

Here is my code, would some one help me? Thanks in advance!

from PyQt5 import QtWidgets, QtCore, QtGui
import sys

pen = QtGui.QPen(QtGui.QColor(0, 24, 128, 200), 10, style=QtCore.Qt.SolidLine, cap=QtCore.Qt.SquareCap)

class Window(QtWidgets.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        central_widget = QtWidgets.QWidget()
        self.scene = QtWidgets.QGraphicsScene(self)
        self.view = QtWidgets.QGraphicsView(self.scene)
        self.view.setSceneRect(self.view.mapToScene(self.view.viewport().rect()).boundingRect())
        self.btn = QtWidgets.QPushButton('Rotate')
        self.btn.clicked.connect(self.animateRotation)
        hbox = QtWidgets.QHBoxLayout(central_widget)
        hbox.addWidget(self.view)
        hbox.addWidget(self.btn)
        self.scene.addEllipse(QtCore.QRectF(0, 0, 100, 250), pen=pen)
        self.view.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.CrossPattern))
        self.setCentralWidget(central_widget)
        print(self.scene.items()[0])

    def rot(self, angle: QtCore.QVariant) -> None:
        self.view.rotate(self.scene.items()[0].rotation()-angle)
        self.scene.items()[0].setRotation(angle)
        
    @QtCore.pyqtSlot()
    def animateRotation(self):
        animation = QtCore.QVariantAnimation()
        animation.setStartValue(QtCore.QVariant(0))
        animation.setEndValue(QtCore.QVariant(45))
        animation.start(QtCore.QAbstractAnimation.DeleteWhenStopped)
        animation.valueChanged.connect(self.rot)
if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

Solution

  • The problem is the life cycle of the animation variable, as it is a local variable, it will only be destroyed as soon as animateRotation finishes executing, that is, as soon as the animation starts, so animation will not work.

    The solution is to extend the life cycle of the variable, and in the case of Qt there are the following options:

    • Make the variable attribute of the class by changing animation to self.animation.

    • Pass a parent that has a longer life cycle to the QVariantAnimation, for example self variable: animation = QtCore.QVariantAnimation(self).