Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gif image in QLabel

I want to add a gif animated image in QLabel that add into the QGraphicsScene. My code is here:

QLabel *lbl = new QLabel;
QMovie *mv = new QMovie(":/Images/sun.gif");
mv->start();
lbl->setWindowFlags(Qt::FramelessWindowHint);
lbl->setMask((new QPixmap(":/Images/sun.gif"))->mask());   // for create transparent for QLabel image
lbl->setMovie(mv);
lbl->setGeometry(10,10,10,10);
scene.addWidget(lbl);

but when I run that it will transparent with first frame of that gif and when the gif is running the photo will not show completely and it will run with transparented area in the first frame. How can I solve that? Thanks

like image 771
Rmin Avatar asked Jul 06 '14 05:07

Rmin


1 Answers

The problem is that QLabel has window background by default. You're trying to remove it by do it incorrectly:

FramelessWindowHint doesn't make sense here, since it's only used for top level widgets, and a widget added to scene is technically hidden and doesn't have system window frame. This line should be removed.

setMask does exactly what you describe it does. Since QPixmap is not animated, its mask is the alpha mask of the first frame of animation. And you permanently apply this mask to the label. It's not surpising that it works, but obviously it's not what you want. This line should also be removed.

setGeometry line is incorrect. It prevents picture from being visible for me. Label has good size by default and there is no need for setGeometry. If you want to scale or move the item on the scene, you can do it after addWidget as for any other QGraphicsItem. E.g. addWidget(lbl)->setPos(10, 10).

The magic bullet you need is WA_NoSystemBackground. It disables background painting for QLabel completely. So, the full code would be:

QLabel *lbl = new QLabel;
QMovie *mv = new QMovie("c:/tmp/sun.gif");
mv->start();
lbl->setAttribute(Qt::WA_NoSystemBackground);
lbl->setMovie(mv);
scene.addWidget(lbl);

It works fine for me. However I consider it over-complicated. You should not use proxy widgets in scene unless necessary. You can easily add a movie using QMovie and QGraphicsPixmapItem and switching pixmaps as movie frames change. I wrote a convenient class for this:

Header:

class GraphicsMovieItem : public QObject, public QGraphicsPixmapItem {
  Q_OBJECT
public:
  GraphicsMovieItem(QGraphicsItem* parent = 0);
  void setMovie(QMovie* movie);

private:
  QMovie* m_movie;

private slots:
  void frameChanged();
};

Source:

GraphicsMovieItem::GraphicsMovieItem(QGraphicsItem *parent)
  : QGraphicsPixmapItem(parent), m_movie(0) {
}

void GraphicsMovieItem::setMovie(QMovie *movie) {
  if (m_movie) {
    disconnect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frameChanged()));
  }
  m_movie = movie;
  if (m_movie) {
    connect(m_movie, SIGNAL(frameChanged(int)), this, SLOT(frameChanged()));
  }
  frameChanged();
}

void GraphicsMovieItem::frameChanged() {
  if (!m_movie) { return; }
  setPixmap(m_movie->currentPixmap());
}

Usage:

QMovie *mv = new QMovie("c:/tmp/sun.gif");
GraphicsMovieItem* item = new GraphicsMovieItem();
item->setMovie(mv);
scene.addItem(item);
like image 194
Pavel Strakhov Avatar answered Oct 15 '22 05:10

Pavel Strakhov