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?

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.2k 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.
  • L Offline
    L Offline
    leonardo M B
    wrote on last edited by leonardo M B
    #1

    I Have Multiples QFrames and each one of them have a particular QPushButton and I'm setting the Icon of each one of the QPushButtons to the same image, but its using a lot of memory.

    Is there any way to use only one QIcon to multiples QPushButtons?

    JonBJ JoeCFDJ 2 Replies Last reply
    0
    • L leonardo M B

      I Have Multiples QFrames and each one of them have a particular QPushButton and I'm setting the Icon of each one of the QPushButtons to the same image, but its using a lot of memory.

      Is there any way to use only one QIcon to multiples QPushButtons?

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

      @leonardo-M-B said in Is there a way of reusing a QIcon in differents QPushButtons?:

      I'm setting the Icon of each one of the QPushButtons to the same image, but its using a lot of memory.

      I wonder what evidence you have for this? However your are setting icons on pushbuttons the image is shared in Qt, so it probably doesn't much matter how you do it I wouldn't expect much memory to be used. You can use a single QIcon if you want, just create it once, I would not have thought this would be significant.

      1 Reply Last reply
      2
      • L leonardo M B

        I Have Multiples QFrames and each one of them have a particular QPushButton and I'm setting the Icon of each one of the QPushButtons to the same image, but its using a lot of memory.

        Is there any way to use only one QIcon to multiples QPushButtons?

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

        @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 1 Reply Last reply
        0
        • 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 Online
                  Chris KawaC Online
                  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 Online
                          Chris KawaC Online
                          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