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
QtWS25 Last Chance

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.
  • A Offline
    A Offline
    artwaw
    wrote on 13 Feb 2021, 13:19 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

    J 1 Reply Last reply 13 Feb 2021, 14:28
    0
    • A artwaw
      13 Feb 2021, 13:19

      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

      J Offline
      J Offline
      JonB
      wrote on 13 Feb 2021, 14:28 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.

      A 1 Reply Last reply 13 Feb 2021, 14:57
      2
      • J JonB
        13 Feb 2021, 14:28

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

        A Offline
        A Offline
        artwaw
        wrote on 13 Feb 2021, 14:57 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
        • C Offline
          C Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on 13 Feb 2021, 14:58 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;
          };
          
          A 2 Replies Last reply 13 Feb 2021, 15:22
          3
          • C Chris Kawa
            13 Feb 2021, 14:58

            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;
            };
            
            A Offline
            A Offline
            artwaw
            wrote on 13 Feb 2021, 15:22 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
            • C Chris Kawa
              13 Feb 2021, 14:58

              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;
              };
              
              A Offline
              A Offline
              artwaw
              wrote on 13 Feb 2021, 17:56 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
              • C Offline
                C Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on 13 Feb 2021, 17:59 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.

                A 1 Reply Last reply 13 Feb 2021, 18:17
                2
                • C Chris Kawa
                  13 Feb 2021, 17:59

                  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.

                  A Offline
                  A Offline
                  artwaw
                  wrote on 13 Feb 2021, 18:17 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

                  4/8

                  13 Feb 2021, 14:58

                  • Login

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