Reputation: 2110
I created a QLabel and set it's movie to a QMovie object with an animated gif. Then in the resizeEvent of my app I resize and move the label, so that it is centered/fit to the layout. This works fine but the movie has a lot of fine lines which get totally garbled in the resize operation, it seems there is no anti-aliasing. So either I am using the wrong resize method, or I need to set anti-aliasing somewhere right? There is nothing in the QMovie or QLabel documentation to suggest how to do this. I did read that the QMovie is inherited from a QImageReader, though that too has no property for anti-aliasing that I could find.
EDIT
I did somewhat get this to work, but it's still not quite right. I found that QMovie has a setScaledSize method which actually scales the underlying QImageViewer. Then I just have the label adjust to it's contents, namely the movie. Using the following code I am able to resize the movie with proper anti-aliasing, however it is quite "jumpy" and "flickery" during resize so obviously I'm not doing this quite "right". Also it somehow loses it's aspect ratio sometimes. Still looking for the correct way to do this... Maybe a QLabel is the wrong way to go?
Here's a working example
import sys
from PyQt4 import QtGui
class MovieTest(QtGui.QDialog):
def __init__(self):
super(MovieTest, self).__init__()
layout = QtGui.QVBoxLayout()
self.setLayout(layout)
self.loading_lbl = QtGui.QLabel()
self.loading_lbl.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicyIgnored)
self.loading_lbl.setScaledContents(True)
layout.addWidget(self.loading_lbl)
loading_movie = QtGui.QMovie("loading-radial_loop.gif") # some gif in here
self.loading_lbl.setMovie(loading_movie)
loading_movie.start()
self.setGeometry(50,50,100,100)
self.setMinimumSize(10,10)
def resizeEvent(self, event):
rect = self.geometry()
size = min(rect.width(), rect.height())
movie = self.loading_lbl.movie()
movie.setScaledSize(QtCore.QSize(size, size))
self.loading_lbl.adjustSize()
def main():
app = QtGui.QApplication(sys.argv)
ex = MovieTest()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Upvotes: 3
Views: 6785
Reputation: 2110
Ok I have this figured out now, with just a few tweaks to the code in my edited post. The secret is in keeping the label the full size of it's parent rect (in this case the size of the whole layout) and then scaling the movie within the label. Essentially you are internally scaling the movie, instead of having it automatically fill the contents of the label. From what I can tell this changes around the order of operations a bit and allows the movie to scale itself on render, instead of rendering the frame and then scaling it to the label size.
Working code:
import sys
from PyQt4 import QtGui, QtCore
class MovieTest(QtGui.QDialog):
def __init__(self):
super(MovieTest, self).__init__()
layout = QtGui.QVBoxLayout()
self.setLayout(layout)
self.loading_lbl = QtGui.QLabel()
self.loading_lbl.setStyleSheet('border: 1px solid red') # just for illustration
self.loading_lbl.setAlignment(QtCore.Qt.AlignCenter)
layout.addWidget(self.loading_lbl)
loading_movie = QtGui.QMovie("loading-radial_loop.gif")
self.loading_lbl.setMovie(loading_movie)
loading_movie.start()
self.setGeometry(50,50,100,100)
self.setMinimumSize(10,10)
def resizeEvent(self, event):
rect = self.geometry()
size = QtCore.QSize(min(rect.width(), rect.height()), min(rect.width(), rect.height()))
movie = self.loading_lbl.movie()
movie.setScaledSize(size)
def main():
app = QtGui.QApplication(sys.argv)
ex = MovieTest()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Upvotes: 6