QPushButton
can have icon, but I need to set animated icon to it. How to do this?
I created new class implemented from QPushButton
but how to replace icon from QIcon
to QMovie
?

- 4,167
- 3
- 25
- 30

- 1,064
- 6
- 17
- 41
2 Answers
This can be accomplished without subclassing QPushButton
by simply using the signal / slot mechanism of Qt. Connect the frameChanged
signal of QMovie
to a custom slot in the class that contains this QPushButton
. This function will apply the current frame of the QMovie
as the icon of the QPushButton
. It should look something like this:
// member function that catches the frameChanged signal of the QMovie
void MyWidget::setButtonIcon(int frame)
{
myPushButton->setIcon(QIcon(myMovie->currentPixmap()));
}
And when allocating your QMovie
and QPushButton
members ...
myPushButton = new QPushButton();
myMovie = new QMovie("someAnimation.gif");
connect(myMovie,SIGNAL(frameChanged(int)),this,SLOT(setButtonIcon(int)));
// if movie doesn't loop forever, force it to.
if (myMovie->loopCount() != -1)
connect(myMovie,SIGNAL(finished()),myMovie,SLOT(start()));
myMovie->start();

- 4,167
- 3
- 25
- 30

- 3,063
- 1
- 23
- 31
-
Thank you very much. Can animation image have transparent background? – Robotex Mar 13 '13 at 11:58
-
You should be able to as far as I know. The GIF format allows for transparency (by specifying a color in the image that should be transparent) and Qt allows for transparent QPixmaps to be drawn over widgets. The only thing I'm unsure of is whether QMovie supports transparency. As Qt classes are normally very thorough it would surprise me if QMovie didn't support transparency, but it mentions nothing about this in the documentation. – Sir Digby Chicken Caesar Mar 13 '13 at 15:27
-
I need two animated icons and change it by situation (when idle - one, when working - another). How can I do this elegant? – Robotex Mar 14 '13 at 10:53
-
Well what I would do is declare two slots; one for the working state movie and one for the idle state movie. Then when switching states, simply call stop() on the previous state's movie and start() on the new state's movie. As the previous state's movie will not be 'playing', its slot will not get called until you start it's playback again. – Sir Digby Chicken Caesar Mar 14 '13 at 17:00
-
Oh, how I did not think of? Thank you very much. You helped :) – Robotex Mar 14 '13 at 23:06
-
3I don't find two-slots solution much elegant. I'd prefer to subclass QPushButton and handle frame changing internally, and switch icons using custom method `setMovie`. I think this would be more elegant and OOP-consistent. – Pavel Strakhov Jun 11 '13 at 20:04
-
With GIFs, I recommend using movie->setCacheMode(QMovie::CacheAll) as well. Without it set I noticed the memory usage continually climb – Wallboy May 28 '18 at 03:58
Since I had to solve this problem for a project of mine today, I just wanted to drop the solution I found for future people, because this question has lots of views and I considered the solution quite elegant. The solution was posted here. It sets the icon of the pushButton every time, the frame of the QMovie changes:
auto movie = new QMovie(this);
movie->setFileName(":/sample.gif");
connect(movie, &QMovie::frameChanged, [=]{
pushButton->setIcon(movie->currentPixmap());
});
movie->start();
This also has the advantage, that the icon will not appear, until the QMovie was started. Here is also the python solution, I derived for my project:
#'hide' the icon on the pushButton
pushButton.setIcon(QIcon())
animated_spinner = QtGui.QMovie(":/icons/images/loader.gif")
animated_spinner.frameChanged.connect(updateSpinnerAniamation)
def updateSpinnerAniamation(self):
#'hide' the text of the button
pushButton.setText("")
pushButton.setIcon(QtGui.QIcon(animated_spinner.currentPixmap()))
Once you want to show the spinner, just start the QMovie:
animated_spinner.start()
If the spinner should disappear again, then stop the animation and 'hide' the spinner again. Once the animation is stopped, the frameChanged slot won't update the button anymore.
animated_spinner.stop()
pushButton.setIcon(QtGui.QIcon())

- 270
- 2
- 6