Animated GIF in QGraphicsScene/QGraphicsView
- 
Good morning, 
 I have QGraphicsScene in QGraphicsView to display and manipulate images. It works well, no issues here. It is the first time I tried QGraphicsScene instead if QLabel and I am very fond of how neatly it all works.
 However I stumbled upon the edge case where animated gif is selected for display - as expected, only the first frame is displayed.
 I tried usual way of having QMovie assigned to QLabel etc. - added that to the scene with addWidget() method but label is not visible.
 This project is built using Qt5.15.2 (macOS clang/win mingw8)So the question: is there any sane way of making it work without me having to rewrite half of the Qt ;) or should I just let go the idea of displaying animated gifs in the scene? As usual, many thanks in advance. 
 Artur
- 
Good morning, 
 I have QGraphicsScene in QGraphicsView to display and manipulate images. It works well, no issues here. It is the first time I tried QGraphicsScene instead if QLabel and I am very fond of how neatly it all works.
 However I stumbled upon the edge case where animated gif is selected for display - as expected, only the first frame is displayed.
 I tried usual way of having QMovie assigned to QLabel etc. - added that to the scene with addWidget() method but label is not visible.
 This project is built using Qt5.15.2 (macOS clang/win mingw8)So the question: is there any sane way of making it work without me having to rewrite half of the Qt ;) or should I just let go the idea of displaying animated gifs in the scene? As usual, many thanks in advance. 
 Artur@artwaw 
 I would search for what others have done to get this working. For example
 https://forum.qt.io/topic/15658/solved-how-to-play-gif-animation-in-qgraphicsview-widget
 https://www.qtcentre.org/threads/61528-How-to-place-animated-GIF-on-QGraphicsScene
 https://stackoverflow.com/a/21083803/489865I think the last one at least is doing it via QMovie/QLabel/QGraphicsScene::addWidget(). So don't know why you seem to say you can't.
- 
@artwaw 
 I would search for what others have done to get this working. For example
 https://forum.qt.io/topic/15658/solved-how-to-play-gif-animation-in-qgraphicsview-widget
 https://www.qtcentre.org/threads/61528-How-to-place-animated-GIF-on-QGraphicsScene
 https://stackoverflow.com/a/21083803/489865I think the last one at least is doing it via QMovie/QLabel/QGraphicsScene::addWidget(). So don't know why you seem to say you can't.
- 
You could certainly use a label, but proxy widgets are a bit heavy. All you really need to do is paint a frame of QMovie, so you can very easily make a custom graphics item that does that. You just need to implement 3 simple methods and you should be good to go, e.g. class GraphicsMovieItem : public QGraphicsItem { public: using QGraphicsItem::QGraphicsItem; void setMovie(QMovie* movie) { prepareGeometryChange(); QObject::disconnect(mConnection); // disconnect old object mMovie = movie; if (mMovie) mConnection = QObject::connect(mMovie, &QMovie::frameChanged, [=]{ update(); }); } QRectF boundingRect() const override { if (mMovie) return mMovie->frameRect(); else return QRectF(); } void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override { if (mMovie) painter->drawPixmap(mMovie->frameRect(), mMovie->currentPixmap(), mMovie->frameRect()); } private: QPointer<QMovie> mMovie; QMetaObject::Connection mConnection; };
- 
You could certainly use a label, but proxy widgets are a bit heavy. All you really need to do is paint a frame of QMovie, so you can very easily make a custom graphics item that does that. You just need to implement 3 simple methods and you should be good to go, e.g. class GraphicsMovieItem : public QGraphicsItem { public: using QGraphicsItem::QGraphicsItem; void setMovie(QMovie* movie) { prepareGeometryChange(); QObject::disconnect(mConnection); // disconnect old object mMovie = movie; if (mMovie) mConnection = QObject::connect(mMovie, &QMovie::frameChanged, [=]{ update(); }); } QRectF boundingRect() const override { if (mMovie) return mMovie->frameRect(); else return QRectF(); } void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override { if (mMovie) painter->drawPixmap(mMovie->frameRect(), mMovie->currentPixmap(), mMovie->frameRect()); } private: QPointer<QMovie> mMovie; QMetaObject::Connection mConnection; };@Chris-Kawa That's smart! I'll definitely try this approach out, thank you! 
- 
You could certainly use a label, but proxy widgets are a bit heavy. All you really need to do is paint a frame of QMovie, so you can very easily make a custom graphics item that does that. You just need to implement 3 simple methods and you should be good to go, e.g. class GraphicsMovieItem : public QGraphicsItem { public: using QGraphicsItem::QGraphicsItem; void setMovie(QMovie* movie) { prepareGeometryChange(); QObject::disconnect(mConnection); // disconnect old object mMovie = movie; if (mMovie) mConnection = QObject::connect(mMovie, &QMovie::frameChanged, [=]{ update(); }); } QRectF boundingRect() const override { if (mMovie) return mMovie->frameRect(); else return QRectF(); } void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override { if (mMovie) painter->drawPixmap(mMovie->frameRect(), mMovie->currentPixmap(), mMovie->frameRect()); } private: QPointer<QMovie> mMovie; QMetaObject::Connection mConnection; };@Chris-Kawa I am sorry to bother you but example code provided raises some issues during the compilation: /Users/arturwawrowski/cpp/build-TNImageViewer-Desktop_Qt_5_15_2_clang_64bit-Debug/moc_qgraphicsmovieitem.cpp:67: error: no member named 'staticMetaObject' in 'QGraphicsItem'; did you mean simply 'staticMetaObject'? moc_qgraphicsmovieitem.cpp:67:34: error: no member named 'staticMetaObject' in 'QGraphicsItem'; did you mean simply 'staticMetaObject'? QMetaObject::SuperData::link<QGraphicsItem::staticMetaObject>(), ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ staticMetaObject moc_qgraphicsmovieitem.cpp:66:58: note: 'staticMetaObject' declared here QT_INIT_METAOBJECT const QMetaObject QGraphicsMovieItem::staticMetaObject = { { ^and several of: /Users/arturwawrowski/cpp/build-TNImageViewer-Desktop_Qt_5_15_2_clang_64bit-Debug/moc_qgraphicsmovieitem.cpp:78: error: invalid use of non-static data member 'd_ptr' moc_qgraphicsmovieitem.cpp:78:21: error: invalid use of non-static data member 'd_ptr' return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; ~~~~~~~~~^~~~~intertwined with: /Users/arturwawrowski/cpp/build-TNImageViewer-Desktop_Qt_5_15_2_clang_64bit-Debug/moc_qgraphicsmovieitem.cpp:78: error: 'd_ptr' is a protected member of 'QObject' moc_qgraphicsmovieitem.cpp:78:21: error: 'd_ptr' is a protected member of 'QObject' ../../Qt/5.15.2/clang_64/lib/QtCore.framework/Headers/qobject.h:450:33: note: declared protected here QScopedPointer<QObjectData> d_ptr; ^Code: 
 header#ifndef QGRAPHICSMOVIEITEM_H #define QGRAPHICSMOVIEITEM_H #include <QGraphicsItem> #include <QObject> #include <QMovie> #include <QPainter> class QGraphicsMovieItem : public QGraphicsItem { Q_OBJECT public: QGraphicsMovieItem(QGraphicsItem *parent = nullptr); void setMovie(QMovie* movie); QRectF boundingRect() const override; void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; private: QPointer<QMovie> mMovie; QMetaObject::Connection mConnection; }; #endif // QGRAPHICSMOVIEITEM_Himplementation: #include "qgraphicsmovieitem.h" QGraphicsMovieItem::QGraphicsMovieItem(QGraphicsItem *parent) : QGraphicsItem(parent) {} void QGraphicsMovieItem::setMovie(QMovie* movie) { prepareGeometryChange(); QObject::disconnect(mConnection); mMovie = movie; if (mMovie) { mConnection = QObject::connect(mMovie, &QMovie::frameChanged, [=]{ update(); }); } } QRectF QGraphicsMovieItem::boundingRect() const { if (mMovie) { return mMovie->frameRect(); } else { return QRectF(); } } void QGraphicsMovieItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(option) Q_UNUSED(widget) if (mMovie) { painter->drawPixmap(mMovie->frameRect(), mMovie->currentPixmap(), mMovie->frameRect()); } }What I did wrong this time? 
- 
QGraphicsItemdoes not inheritQObjectso don't useQ_OBJECTfor your class.Btw. modern C++ has this wonderful thing called inherited constructors, so you don't have to write the boilerplate empty constructors that just pass parameters to base classes. Instead of writing QGraphicsMovieItem(QGraphicsItem *parent = nullptr);and implementing it as an empty method you can just writeusing QGraphicsItem::QGraphicsItem;and it does exactly the same thing. Super useful when base class has multiple constructors with different parameters as you can inherit them all in just that one line.
- 
QGraphicsItemdoes not inheritQObjectso don't useQ_OBJECTfor your class.Btw. modern C++ has this wonderful thing called inherited constructors, so you don't have to write the boilerplate empty constructors that just pass parameters to base classes. Instead of writing QGraphicsMovieItem(QGraphicsItem *parent = nullptr);and implementing it as an empty method you can just writeusing QGraphicsItem::QGraphicsItem;and it does exactly the same thing. Super useful when base class has multiple constructors with different parameters as you can inherit them all in just that one line.@Chris-Kawa Noted thank you. Now it compiles without errors. I think I need to read a bit about newer c++... 
 
