cap
cap

Reputation: 21

How do I animate the scene Rectangle?

I am trying to move my QGraphicsScene rectangle using a animation to get the impression that it moves smoothly. But I don't know how to do it works. Could some one help me? I would like to konow if its possible to animate a Qtransform instance. if it is, how can I do that?

Issues:

1 - How animate the translate function, which moves my scene rectangle. I want to animate it, because I want that it looks smooth.

2 - It's possible to animate a Qtransform instance?

here is my code:

from PyQt5.QtWidgets import QWidget, QApplication, QHBoxLayout
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5 import QtCore


class Example(QWidget):

    def __init__(self, parent=None):
        super(Example, self).__init__(parent) # this widget has no parent
        hbox = QHBoxLayout(self)
        self.setMinimumHeight(500)
        self.setMinimumWidth(500)
        self.button = QtWidgets.QPushButton("move scene", self)  # this button is responsible to emit a signal to animate the
        # scene translation
        self.button.clicked.connect(self.do)  # connect to the animation
        self.scene = QtWidgets.QGraphicsScene()  # instantiate the scene
        self.view = QtWidgets.QGraphicsView(self)  # instantiate the view
        self.view.setScene(self.scene)
        hbox.addWidget(self.view)  # insert into the layout
        hbox.addWidget(self.button)  # insert into the layout
        self.r = self.view.mapToScene(self.view.viewport().rect()).boundingRect()# take the viewport bounding rectangle
        self.view.setSceneRect(self.r)  # define the viewport bounding rectangle as the initial scene rectangle
        self.scene.addEllipse(self.r, QtGui.QPen(QtGui.QBrush(QtCore.Qt.darkRed), 10, join=QtCore.Qt.RoundJoin))
        # draw an ellipse in our scene
        self.scene.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.CrossPattern))  # set a grid patter to turn easier to
        # see the displacements of objects

    def translateSceneSmooth(self, ds: tuple) -> None:
        """
        ds = (dx, dy)
        :param ds: is the differential in x and y.
        :return: None
        """
        self.view.setSceneRect(self.view.sceneRect().translated(*ds)) # I want  that the animation pass a interpolation
        # of a tuple here: starting at (0, 0) and ending at (100, 100)
        # I don't know if this approach is correct.
        # Because maybe it will not  move 100 px.if I have a list of numbers in the form passing through the function:
        # [0, 10, 20, 50, 70, 100] maybe it'll move 0+10+20+50+70+100 = 250 px

    def do(self, duration=100):
        """
        I want the  scene rectangle to move smoothly
        """
        print('Starting animation')
        self._animation = QtCore.QVariantAnimation()
        self._animation.setStartValue(0)
        self._animation.setEndValue(1000)
        self._animation.setDuration(duration)
        self._animation.start(QtCore.QAbstractAnimation.DeleteWhenStopped)
        self._animation.valueChanged.connect(self.translateSceneSmooth)
        print('Ending animation')


if __name__ == "__main__":
    app = QApplication([])
    ex = Example()
    ex.show()
    app.exec_()

Upvotes: 0

Views: 164

Answers (1)

eyllanesc
eyllanesc

Reputation: 244301

If you want to move the sceneRect, generate an animation of the rectangle by calculating the starting and ending rectangles. On the other hand, by default, the pressed signal passes a boolean that overrides the default value of "duration", a possible solution is to use the pyqtSlot decorator to make the connection signature explicit:

from PyQt5 import QtCore, QtGui, QtWidgets


class Example(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Example, self).__init__(parent)

        self.setMinimumSize(500, 500)
        self.button = QtWidgets.QPushButton("move scene")
        # scene translation
        self.button.clicked.connect(self.do)
        self.scene = QtWidgets.QGraphicsScene()
        self.view = QtWidgets.QGraphicsView()
        self.view.setScene(self.scene)

        hbox = QtWidgets.QHBoxLayout(self)
        hbox.addWidget(self.view)
        hbox.addWidget(self.button)

        self.r = self.view.mapToScene(self.view.viewport().rect()).boundingRect()
        self.view.setSceneRect(self.r)
        self.scene.addEllipse(
            self.r,
            QtGui.QPen(QtGui.QBrush(QtCore.Qt.darkRed), 10, join=QtCore.Qt.RoundJoin),
        )
        self.scene.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.CrossPattern))

    @QtCore.pyqtSlot()
    def do(self, duration=100):
        """
        I want the  scene rectangle to move smoothly
        """
        ds = QtCore.QPointF(100, 100)

        current_rect = self.view.sceneRect()
        next_rect = current_rect.translated(ds)
        self._animation = QtCore.QVariantAnimation()
        self._animation.setStartValue(current_rect)
        self._animation.setEndValue(next_rect)
        self._animation.setDuration(duration)
        self._animation.valueChanged.connect(self.view.setSceneRect)
        self._animation.finished.connect(lambda: print("Ending animation"))
        self._animation.start(QtCore.QAbstractAnimation.DeleteWhenStopped)
        print("Starting animation")


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    ex = Example()
    ex.show()
    app.exec_()

Upvotes: 2

Related Questions