simple image slide show using property animations
As a home developer this is my first post to any development forum. Although I am using Python this was the best QT forum I could find so apologies : but my question is probably applicable to c++ as well.
I think I must be missing something with animations.
I am trying to use a QtWidgets.QLabel (lblPhotoDisplay) containing an image to create a simple animated slide show using fade/unfade methods (see below). Chaining the methods using the animation.finished trigger seemed the obvious (to me at least) way to achieve this.
I am calling the fade method from a displayImage method and using the animation.finished trigger to change the image then call the unfade method which unfades with its animation.finshed submitting a job to change the image again at a specified time.
My problem is that everything works OK first time the fade animation is called. Subsequent calls fail to trigger fade animation.finished.
What am I missing -- do animation not chain like this?
def fade(self):
self.effect = QGraphicsOpacityEffect()
self.lblPhotoDisplay.setGraphicsEffect(self.effect )
self.animation = QtCore.QPropertyAnimation(self.effect, b"opacity")
self.animation.setDuration(1000)
self.animation.setStartValue(1)
self.animation.setEndValue(0)
self.animation.finished.connect(self.changeImage)
self.animation.start()
def unfade(self):
self.effect = QGraphicsOpacityEffect()
self.lblPhotoDisplay.setGraphicsEffect(self.effect )
self.animation = QtCore.QPropertyAnimation(self.effect, b"opacity")
self.animation.setDuration(1000)
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.finished.connect(self.nextImage)
self.animation.start()
Re: simple image slide show using property animations
My first impression is that almost all of the "setup" code here:
Code:
self.effect = QGraphicsOpacityEffect()
self.lblPhotoDisplay.setGraphicsEffect(self.effect )
self.animation = QtCore.QPropertyAnimation(self.effect, b"opacity")
self.animation.setDuration(1000)
self.animation.setStartValue(1)
self.animation.setEndValue(0)
self.animation.finished.connect(self.changeImage)
should be in the __init__ method of your class. You do not need to create the animation, connect slots, etc. every time you want to fade or unfade. In __init__ you should create the animation, set the graphics effect, etc. and the only thing you do in the fade() and unfade() methods is to set the direction of the property change:
Code:
def __init__( self ) :
self.effect = QGraphicsOpacityEffect()
self.lblPhotoDisplay.setGraphicsEffect(self.effect )
self.animation = QtCore.QPropertyAnimation(self.effect, b"opacity")
self.animation.setDuration(1000)
self.animation.finished.connect(self.animationFinished)
self.fadeDirection = 0
def fade(self):
self.animation.setStartValue(1)
self.animation.setEndValue(0)
self.fadeDirection = 0
self.animation.start()
def unfade(self):
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.fadeDirection = 1
self.animation.start()
@Slot()
def animationFinished( self )
if self.fadeDirection == 0 :
self.changeImage()
else :
seld.nextImage()
The way your code is written, you are creating a new animation instance every time the fade() or unfade() methods are called and connecting that new instance to one of your two slots. Basically, you are creating two animation instances for every picture and building a rat's nest of signal / slot connections between them. Most QObject-based classes in Qt are generally best created once and reused, and signals and slots connected once, in a constructor.
Re: simple image slide show using property animations
Thanks - d_stanz:
Rewrote the code as per your suggestion (much better) and although it made no difference to the operation of the animation your suggestion set me on the path to finding the issue. I then switched to debugging in visual studio code on windows (deploying to the pi later) rather than directly on the Raspberry pi. This showed that the animation was running in a separate thread second time around -- as result of using apscheduler and pydispatch to manage the timed image change. Worked perfectly when I got it running on the main thread. The apscheduler and pydispatch mechanism was carried over from a previous development of message Queue based sensor stations that don't have GUI components. Will now remove pydispatch and use signals /slots.
Thanks again
Re: simple image slide show using property animations
In Qt (at least the C++ implementation, which I am sure the Python implementation is just layered on top of), all GUI activity has to occur in the main thread (the one that holds the QApplication instance). You can do other Qt things in threads (like manipulate images and such) but when it comes to displaying them, that has to happen in the main thread.
Re: simple image slide show using property animations
What was interesting this time was there was no exception raised, as has been true on the other occasions I have tried to update the ui from a different thread. That's why I thought it was my understanding rather than a problem with my code. Thanks