Reputation: 21
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
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