我如何为场景矩形设置动画?

问题描述

我正在尝试使用动画移动我的 QGraphicsScene 矩形以获得它平滑移动的印象。但我不知道该怎么做。有人可以帮助我吗?我想知道是否可以为 Qtransform 实例设置动画。如果是,我该怎么做?

问题:

1 - 如何为移动我的场景矩形的 translate 函数设置动画。我想为它设置动画,因为我希望它看起来很平滑。

2 - 可以为 Qtransform 实例设置动画吗?

这是我的代码

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,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_()

解决方法

如果要移动sceneRect,通过计算开始和结束矩形来生成矩形的动画。另一方面,默认情况下,按下的信号会传递一个布尔值来覆盖“duration”的默认值,一个可能的解决方案是使用 pyqtSlot 装饰器使连接签名显式:

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_()