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 14 Feb 2023, 21:34 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?

    J J 2 Replies Last reply 14 Feb 2023, 21:48
    0
    • L leonardo M B
      14 Feb 2023, 21:34

      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?

      J Offline
      J Offline
      JonB
      wrote on 14 Feb 2023, 21:48 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
        14 Feb 2023, 21:34

        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?

        J Online
        J Online
        JoeCFD
        wrote on 14 Feb 2023, 22:12 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

        J 1 Reply Last reply 14 Feb 2023, 22:24
        0
        • J JoeCFD
          14 Feb 2023, 22:12

          @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

          J Offline
          J Offline
          JonB
          wrote on 14 Feb 2023, 22:24 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?

          J 1 Reply Last reply 14 Feb 2023, 22:31
          0
          • J JonB
            14 Feb 2023, 22:24

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

            J Online
            J Online
            JoeCFD
            wrote on 14 Feb 2023, 22:31 last edited by
            #5

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

            J 1 Reply Last reply 14 Feb 2023, 22:37
            0
            • J JoeCFD
              14 Feb 2023, 22:31

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

              J Offline
              J Offline
              JonB
              wrote on 14 Feb 2023, 22:37 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?

              J 1 Reply Last reply 14 Feb 2023, 23:09
              0
              • J JonB
                14 Feb 2023, 22:37

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

                J Online
                J Online
                JoeCFD
                wrote on 14 Feb 2023, 23:09 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.

                J 1 Reply Last reply 15 Feb 2023, 08:37
                0
                • C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 14 Feb 2023, 23:50 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 15 Feb 2023, 12:18
                  3
                  • J JoeCFD
                    14 Feb 2023, 23:09

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

                    J Offline
                    J Offline
                    JonB
                    wrote on 15 Feb 2023, 08:37 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.

                    J 1 Reply Last reply 15 Feb 2023, 17:40
                    3
                    • C Chris Kawa
                      14 Feb 2023, 23:50

                      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 15 Feb 2023, 12:18 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

                      J C 2 Replies Last reply 15 Feb 2023, 12:26
                      0
                      • L leonardo M B
                        15 Feb 2023, 12:18

                        @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

                        J Offline
                        J Offline
                        JonB
                        wrote on 15 Feb 2023, 12:26 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
                          15 Feb 2023, 12:18

                          @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

                          C Offline
                          C Offline
                          Chris Kawa
                          Lifetime Qt Champion
                          wrote on 15 Feb 2023, 14:15 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
                          • J JonB
                            15 Feb 2023, 08:37

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

                            J Online
                            J Online
                            JoeCFD
                            wrote on 15 Feb 2023, 17:40 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

                            3/13

                            14 Feb 2023, 22:12

                            topic:navigator.unread, 10
                            • Login

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