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. Is there a way of reusing a QIcon in differents QPushButtons?
Forum Updated to NodeBB v4.3 + New Features

Is there a way of reusing a QIcon in differents QPushButtons?

Scheduled Pinned Locked Moved Unsolved General and Desktop
qpushbuttonqicon
13 Posts 4 Posters 1.4k Views 2 Watching
  • 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.
  • JoeCFDJ JoeCFD

    @leonardo-M-B I guess not. setIcon uses a copy of your icon. Each button has its own copy.
    https://doc.qt.io/qt-5.15/qabstractbutton.html#icon-prop

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

    @JoeCFD
    But how much is anyone saying that costs? Implicitly Shared Classes. There are a bunch of buttons all using the same icon images. Else there wouldn't be much point in having shared data classes?

    JoeCFDJ 1 Reply Last reply
    0
    • JonBJ JonB

      @JoeCFD
      But how much is anyone saying that costs? Implicitly Shared Classes. There are a bunch of buttons all using the same icon images. Else there wouldn't be much point in having shared data classes?

      JoeCFDJ Offline
      JoeCFDJ Offline
      JoeCFD
      wrote on last edited by
      #5

      @JonB It is a copy.
      https://codebrowser.dev/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN15QAbstractButton7setIconERK5QIcon

      JonBJ 1 Reply Last reply
      0
      • JoeCFDJ JoeCFD

        @JonB It is a copy.
        https://codebrowser.dev/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN15QAbstractButton7setIconERK5QIcon

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

        @JoeCFD
        I don't see how we are talking about the same thing. What does your link show? Yes it is a copy of a QIcon. The question is how much is that? The point is it does not contain a copy of the image (unless something odd is going on, OP should only need one pixmap). You have not commented on the shared data, so where is this going?

        As for the original question, since setIcon() takes a copy of the QIcon passed to it there is the answer.

        Is there any evidence that multiple push buttons having the same image is using multiple times the image's size?

        JoeCFDJ 1 Reply Last reply
        0
        • JonBJ JonB

          @JoeCFD
          I don't see how we are talking about the same thing. What does your link show? Yes it is a copy of a QIcon. The question is how much is that? The point is it does not contain a copy of the image (unless something odd is going on, OP should only need one pixmap). You have not commented on the shared data, so where is this going?

          As for the original question, since setIcon() takes a copy of the QIcon passed to it there is the answer.

          Is there any evidence that multiple push buttons having the same image is using multiple times the image's size?

          JoeCFDJ Offline
          JoeCFDJ Offline
          JoeCFD
          wrote on last edited by JoeCFD
          #7

          @JonB There is some sharing mechanism there when I look at QIcon class. I have not got how it is done. Will look more into the code. I am wrong at the copy thing. It looks like a copy, but actually is not.

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

            As @JonB mentioned QIcon is implicitly shared, so copying it does not copy the underlying image data. Only some basic data like number of images contained and a pointer to the pixmap is actually duplicated (a couple bytes at most).

            Something like this will not duplicate the image data:

            QIcon ico(path);
            QPushButton btn1(ico, text);
            QPushButton btn2(ico, text);
            

            Thanks to QPixmap also being implicitly shared this won't either:

            QPixmap pix(path);
            QPushButton btn1(pix, text); // using QIcon(const QPixmap&) implicit constructor
            QPushButton btn2(pix, text);
            

            And not even this, because QPixmap uses QPixmapCache underneath and only loads image once, based on its path and modification date:

            QPushButton btn1(QPixmap (path), text);
            QPushButton btn2(QPixmap (path), text);
            

            You have to actually do some work to force it to duplicate, e.g.

            QPixmap pix(path);
            QPushButton btn1(pix, text);
            pix.detach(); // force pixmap to clone shared data
            QPushButton btn2(pix, text);
            

            Another way this can happen is if your image does not fit in the cache (image is too big or there are a lot of smaller images loaded). The default is 10MB. If you're blowing past the cache size you can increase it via QPixmapCache::setCacheLimit(int). It's a bit counterintuitive, but increasing that size can reduce your overall memory usage if you have a lot of images in your app, because the sharing takes place more often.

            L 1 Reply Last reply
            3
            • JoeCFDJ JoeCFD

              @JonB There is some sharing mechanism there when I look at QIcon class. I have not got how it is done. Will look more into the code. I am wrong at the copy thing. It looks like a copy, but actually is not.

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

              @JoeCFD
              When that referenced code goes d->icon = icon; this invokes QIcon's copy constructor. That is https://codebrowser.dev/qt5/qtbase/src/gui/image/qicon.cpp.html#_ZN5QIconaSERKS_

              QIcon &QIcon::operator=(const QIcon &other)
              {
                  if (other.d)
                      other.d->ref.ref();
                  if (d && !d->ref.deref())
                      delete d;
                  d = other.d;
                  return *this;
              }
              

              See how that works on incrementing/decrementing reference count rather than actually copying the icon's image pixmap.

              The upshot is that copying QIcon neither uses much space nor much time. Qt does this for most of its "BLOB" classes (images, byte arrays, strings, ...). Have a read of Implicit Sharing, it's useful to know about

              Many C++ classes in Qt use implicit data sharing to maximize resource usage and minimize copying. Implicitly shared classes are both safe and efficient when passed as arguments, because only a pointer to the data is passed around, and the data is copied only if and when a function writes to it, i.e., copy-on-write.

              JoeCFDJ 1 Reply Last reply
              3
              • Chris KawaC Chris Kawa

                As @JonB mentioned QIcon is implicitly shared, so copying it does not copy the underlying image data. Only some basic data like number of images contained and a pointer to the pixmap is actually duplicated (a couple bytes at most).

                Something like this will not duplicate the image data:

                QIcon ico(path);
                QPushButton btn1(ico, text);
                QPushButton btn2(ico, text);
                

                Thanks to QPixmap also being implicitly shared this won't either:

                QPixmap pix(path);
                QPushButton btn1(pix, text); // using QIcon(const QPixmap&) implicit constructor
                QPushButton btn2(pix, text);
                

                And not even this, because QPixmap uses QPixmapCache underneath and only loads image once, based on its path and modification date:

                QPushButton btn1(QPixmap (path), text);
                QPushButton btn2(QPixmap (path), text);
                

                You have to actually do some work to force it to duplicate, e.g.

                QPixmap pix(path);
                QPushButton btn1(pix, text);
                pix.detach(); // force pixmap to clone shared data
                QPushButton btn2(pix, text);
                

                Another way this can happen is if your image does not fit in the cache (image is too big or there are a lot of smaller images loaded). The default is 10MB. If you're blowing past the cache size you can increase it via QPixmapCache::setCacheLimit(int). It's a bit counterintuitive, but increasing that size can reduce your overall memory usage if you have a lot of images in your app, because the sharing takes place more often.

                L Offline
                L Offline
                leonardo M B
                wrote on last edited by leonardo M B
                #10

                @Chris-Kawa @JonB
                In Practice I have this situation

                button1->setIcon(QIcon(":/close.png"));
                button2->setIcon(QIcon(":/close.png"));
                button3->setIcon(QIcon(":/close.png"));
                .
                .
                button911->setIcon(QIcon(":/close.png"));
                

                This is also not a problem? I think I understood yours argumentations but I would like to confirm

                JonBJ Chris KawaC 2 Replies Last reply
                0
                • L leonardo M B

                  @Chris-Kawa @JonB
                  In Practice I have this situation

                  button1->setIcon(QIcon(":/close.png"));
                  button2->setIcon(QIcon(":/close.png"));
                  button3->setIcon(QIcon(":/close.png"));
                  .
                  .
                  button911->setIcon(QIcon(":/close.png"));
                  

                  This is also not a problem? I think I understood yours argumentations but I would like to confirm

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

                  @leonardo-M-B
                  Hmm, I wondered if you might have something like this.... I am not sure, but those may [well] be creating separate images for each icon (which might explain the surprise I found in your report). I would try:

                  QIcon close(QIcon(":/close.png"));
                  button1->setIcon(close);
                  button2->setIcon(close);
                  button3->setIcon(close);
                  

                  Does that perchance make your report of "lots of memory" go away?

                  1 Reply Last reply
                  2
                  • L leonardo M B

                    @Chris-Kawa @JonB
                    In Practice I have this situation

                    button1->setIcon(QIcon(":/close.png"));
                    button2->setIcon(QIcon(":/close.png"));
                    button3->setIcon(QIcon(":/close.png"));
                    .
                    .
                    button911->setIcon(QIcon(":/close.png"));
                    

                    This is also not a problem? I think I understood yours argumentations but I would like to confirm

                    Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by Chris Kawa
                    #12

                    @leonardo-M-B Huh, unfortunately QIcon(const QString&) uses a different path in code. It does lookup for scaled images and ultimately does not use pixmap cache, so it will duplicate.

                    That's a bit of a shame actually. QPixmapIconEngine used in that constructor seems to be doing a roundtrip through QImage instead of directly using QPixmap, which bypasses the QPixmapCache optimization.

                    So either use a QPixmap constructor or like @JonB suggested create a single instance of QIcon and reuse it. Copying it will not duplicate data.

                    1 Reply Last reply
                    1
                    • JonBJ JonB

                      @JoeCFD
                      When that referenced code goes d->icon = icon; this invokes QIcon's copy constructor. That is https://codebrowser.dev/qt5/qtbase/src/gui/image/qicon.cpp.html#_ZN5QIconaSERKS_

                      QIcon &QIcon::operator=(const QIcon &other)
                      {
                          if (other.d)
                              other.d->ref.ref();
                          if (d && !d->ref.deref())
                              delete d;
                          d = other.d;
                          return *this;
                      }
                      

                      See how that works on incrementing/decrementing reference count rather than actually copying the icon's image pixmap.

                      The upshot is that copying QIcon neither uses much space nor much time. Qt does this for most of its "BLOB" classes (images, byte arrays, strings, ...). Have a read of Implicit Sharing, it's useful to know about

                      Many C++ classes in Qt use implicit data sharing to maximize resource usage and minimize copying. Implicitly shared classes are both safe and efficient when passed as arguments, because only a pointer to the data is passed around, and the data is copied only if and when a function writes to it, i.e., copy-on-write.

                      JoeCFDJ Offline
                      JoeCFDJ Offline
                      JoeCFD
                      wrote on last edited by JoeCFD
                      #13

                      @JonB d->icon = icon; this invokes QIcon's equal operator =(). You are right: QIcon has some sort of reference count. I will have a detailed look at it.

                      1 Reply Last reply
                      0

                      • Login

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