Как установить анимированный значок на QPushButton в Qt5?

QPushButton может иметь значок, но мне нужно установить для него анимированный значок. Как это сделать? Я создал новый класс, реализованный из QPushButton, но как заменить значок с QIcon на QMovie?


person Robotex    schedule 12.03.2013    source источник


Ответы (2)


Поскольку сегодня мне нужно было решить эту проблему для моего проекта, я просто хотел отбросить найденное решение для будущих людей, потому что у этого вопроса много просмотров, и я посчитал решение довольно элегантным. Решение опубликовано здесь. Он устанавливает значок кнопки каждый раз, когда изменяется кадр QMovie:

auto movie = new QMovie(this);
movie->setFileName(":/sample.gif");
connect(movie, &QMovie::frameChanged, [=]{
  pushButton->setIcon(movie->currentPixmap());
});
movie->start();

Это также имеет то преимущество, что значок не появится до тех пор, пока не будет запущен QMovie. Вот также решение Python, которое я получил для своего проекта:

#'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()))

Как только вы захотите показать счетчик, просто запустите QMovie:

animated_spinner.start()

Если счетчик должен снова исчезнуть, остановите анимацию и снова «скройте» счетчик. Как только анимация остановлена, слот frameChanged больше не будет обновлять кнопку.

animated_spinner.stop()
pushButton.setIcon(QtGui.QIcon())
person captainmoron    schedule 15.12.2020

Этого можно добиться без создания подкласса QPushButton, просто используя механизм сигналов/слотов Qt. Подключите сигнал frameChanged QMovie к пользовательскому слоту в классе, который содержит этот QPushButton. Эта функция применит текущий кадр QMovie в качестве значка QPushButton. Это должно выглядеть примерно так:

// member function that catches the frameChanged signal of the QMovie
void MyWidget::setButtonIcon(int frame)
{
    myPushButton->setIcon(QIcon(myMovie->currentPixmap()));
}

И при распределении ваших QMovie и QPushButton участников...

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();
person Sir Digby Chicken Caesar    schedule 13.03.2013
comment
Большое тебе спасибо. Может ли анимационное изображение иметь прозрачный фон? - person Robotex; 13.03.2013
comment
Вы должны быть в состоянии, насколько я знаю. Формат GIF допускает прозрачность (путем указания цвета изображения, которое должно быть прозрачным), а Qt позволяет рисовать прозрачные QPixmap поверх виджетов. Единственное, в чем я не уверен, так это в том, поддерживает ли QMovie прозрачность. Поскольку классы Qt обычно очень тщательны, меня бы удивило, если бы QMovie не поддерживал прозрачность, но в документации ничего об этом не упоминается. - person Sir Digby Chicken Caesar; 13.03.2013
comment
Мне нужно две анимированные иконки и менять их по ситуации (при простое - одна, при работе - другая). Как я могу сделать это элегантно? - person Robotex; 14.03.2013
comment
Ну, что я бы сделал, так это объявил два слота; один для фильма в рабочем состоянии и один для фильма в состоянии ожидания. Затем при переключении состояний просто вызовите stop() для фильма предыдущего состояния и start() для фильма нового состояния. Поскольку фильм в предыдущем состоянии не будет «проигрываться», его слот не будет вызываться до тех пор, пока вы снова не начнете его воспроизведение. - person Sir Digby Chicken Caesar; 14.03.2013
comment
О, как я не догадался? Большое тебе спасибо. Вы помогли :) - person Robotex; 15.03.2013
comment
Я не нахожу решение с двумя слотами очень элегантным. Я бы предпочел создать подкласс QPushButton и обрабатывать изменение кадра внутри, а также переключать значки с помощью пользовательского метода setMovie. Я думаю, что это было бы более элегантно и совместимо с ООП. - person Pavel Strakhov; 12.06.2013
comment
С GIF-файлами я также рекомендую использовать movie-›setCacheMode(QMovie::CacheAll). Без его установки я заметил, что использование памяти постоянно растет - person Wallboy; 28.05.2018