Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Animated GIF in QGraphicsScene/QGraphicsView

Animated GIF in QGraphicsScene/QGraphicsView

Scheduled Pinned Locked Moved Solved General and Desktop
qgraphicssceneqgraphicsviewqmoviegifanimations
8 Posts 3 Posters 6.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • artwawA Offline
    artwawA Offline
    artwaw
    wrote on last edited by
    #1

    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

    For more information please re-read.

    Kind Regards,
    Artur

    JonBJ 1 Reply Last reply
    0
    • artwawA artwaw

      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

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @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/489865

      I 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.

      artwawA 1 Reply Last reply
      2
      • JonBJ JonB

        @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/489865

        I 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.

        artwawA Offline
        artwawA Offline
        artwaw
        wrote on last edited by
        #3

        @JonB Thanks. This didn't popup (first result seems the way to go) when I used search in the forum O_O

        For more information please re-read.

        Kind Regards,
        Artur

        1 Reply Last reply
        0
        • Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by Chris Kawa
          #4

          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;
          };
          
          artwawA 2 Replies Last reply
          3
          • Chris KawaC Chris Kawa

            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;
            };
            
            artwawA Offline
            artwawA Offline
            artwaw
            wrote on last edited by
            #5

            @Chris-Kawa That's smart! I'll definitely try this approach out, thank you!

            For more information please re-read.

            Kind Regards,
            Artur

            1 Reply Last reply
            0
            • Chris KawaC Chris Kawa

              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;
              };
              
              artwawA Offline
              artwawA Offline
              artwaw
              wrote on last edited by
              #6

              @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_H
              

              implementation:

              #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?

              For more information please re-read.

              Kind Regards,
              Artur

              1 Reply Last reply
              0
              • Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by Chris Kawa
                #7

                QGraphicsItem does not inherit QObject so don't use Q_OBJECT for 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 write using 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.

                artwawA 1 Reply Last reply
                2
                • Chris KawaC Chris Kawa

                  QGraphicsItem does not inherit QObject so don't use Q_OBJECT for 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 write using 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.

                  artwawA Offline
                  artwawA Offline
                  artwaw
                  wrote on last edited by
                  #8

                  @Chris-Kawa Noted thank you. Now it compiles without errors. I think I need to read a bit about newer c++...

                  For more information please re-read.

                  Kind Regards,
                  Artur

                  1 Reply Last reply
                  1

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved