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. Toggle svg icon on Button click - QT C++
Forum Updated to NodeBB v4.3 + New Features

Toggle svg icon on Button click - QT C++

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 Posters 3.2k Views 1 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.
  • R Offline
    R Offline
    Rizwan94
    wrote on 30 Dec 2019, 16:54 last edited by
    #1

    Hi,

    I am relatively new to svg + QT concepts.
    I have created an svg icon which has 2 states.
    I want to add this svg icon to a QPushButton. When the button is clicked,the icon should get toggled ( show the other state ).

    Can anybody pls give me a heads up on how to do this in QT? QT with C++!

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 30 Dec 2019, 17:06 last edited by
      #2

      Hi,

      Take a look at QIcon.

      It's what you need to setup in order to have the various icons used automatically when the button state changes.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      3
      • R Offline
        R Offline
        Rizwan94
        wrote on 2 Jan 2020, 14:03 last edited by
        #3

        Hi @SGaist ,
        I have tried something using the QSvgRenderer and QIcon.
        I have achieved what I was looking for.

        But I am not sure if this is how it should be done.
        Please have a look and let me know if this is the preferred way or not.


        I have created a svg icon ( using 2 other svg icons ) from the https://nucleoapp.com/tool/icon-transition
        The svg icon has 2 svg icons embedded into it. My objective now is to toggle the icons when button is clicked.

        Checkout my files below

        #ifndef MAINWINDOW_H
        #define MAINWINDOW_H
        
        #include <QMainWindow>
        #include <QSvgRenderer>
        
        namespace Ui {
        class MainWindow;
        }
        
        class MainWindow : public QMainWindow
        {
            Q_OBJECT
        
        public:
            explicit MainWindow(QWidget *parent = nullptr);
            ~MainWindow();
        
        private:
            Ui::MainWindow *ui;
            bool isDefaultIconLoaded;
            QString otherIconSvgContent;
            QString defaultIconSvgContent;
        
            QSvgRenderer m_svgRenderer;
        
            void loadCurrentSvgIcon(QByteArray ba);
        
        private slots:
            void toolBtnClicked();
        };
        
        #endif // MAINWINDOW_H
        
        

        The cpp file

        #include "mainwindow.h"
        #include "ui_mainwindow.h"
        #include <QFile>
        #include <QPainter>
        #include <QtSvg/QSvgRenderer>
        #include <QPixmap>
        #include <QDomDocument>
        #include <QDomNodeList>
        #include <QTextStream>
        #include <QDebug>
        
        MainWindow::MainWindow(QWidget *parent) :
            QMainWindow(parent),
            ui(new Ui::MainWindow),
            isDefaultIconLoaded(true)
        {
            ui->setupUi(this);;
            connect(ui->toolButton, &QToolButton::clicked, this, &MainWindow::toolBtnClicked);
            ui->toolButton->setStyleSheet("border:none;");
        
            // open svg icon which has multiple states
            QFile file(":/icon/theSvg.svg");
            file.open(QIODevice::ReadOnly);
            const QByteArray baData = file.readAll();
            QDomDocument doc;
            doc.setContent(baData, false);
        
            // Read both the <g> elements from the .svg xml and store each 'icon content' in member var.
            QDomNodeList gList = doc.elementsByTagName("g");
            for(int i = 0; i < gList.size(); i++)
            {
                QString aContent;
                QTextStream ts(&aContent);
                gList.at(i).save(ts,0);
                qDebug("%s", qPrintable(aContent));
        
                if( isDefaultIconLoaded )
                {
                    defaultIconSvgContent.insert(0, "<svg>");
                    defaultIconSvgContent += aContent;;
                    defaultIconSvgContent.append("</svg>");
                    isDefaultIconLoaded = false;
                    qDebug() <<defaultIconSvgContent;
                }
                else {
                    otherIconSvgContent.insert(0, "<svg>");
                    otherIconSvgContent += aContent;
                    otherIconSvgContent.append("</svg>");
                    qDebug() <<otherIconSvgContent;
                }
            }
        
            // Load the default svg icon first
           QByteArray ba = defaultIconSvgContent.toUtf8();
           isDefaultIconLoaded = true;
           loadCurrentSvgIcon(ba);
        }
        
        MainWindow::~MainWindow()
        {
            delete ui;
        }
        
        void MainWindow::loadCurrentSvgIcon(QByteArray ba)
        {
           m_svgRenderer.load(ba);
           QPixmap pix(m_svgRenderer.defaultSize());
            QPainter pixPainter(&pix);
            m_svgRenderer.render(&pixPainter);
            QIcon myicon(pix);
        
            ui->toolButton->setIcon(myicon);
        }
        
        void MainWindow::toolBtnClicked()
        {
            if ( isDefaultIconLoaded == true )
            {
                // Toggle the icon to "other"
                QByteArray ba = otherIconSvgContent.toUtf8();
                loadCurrentSvgIcon(ba);
                isDefaultIconLoaded = false;
            }
            else {
                QByteArray ba = defaultIconSvgContent.toUtf8();
                loadCurrentSvgIcon(ba);
                isDefaultIconLoaded = true;
            }
        }
        

        Content of the svg file

        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" height="16" width="16">
            <g 
              class="nc-icon-wrapper" stroke-width="1" fill="#111111" stroke="#111111">
              <title>default</title>
            <path 
              fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" data-color="color-2" d="M1.5 1.5h2">      
            </path>
            <circle 
              fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" cx="9" cy="9" r="3.5" data-color="color-2">
            </circle>
              <path 
                fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" data-color="color-2" d="M2.5 5.5h1">        
              </path>
              <path 
                fill="none" stroke="#111111" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M14.5 3.5h-2l-1-2h-5l-1 2h-4a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h13a1 1 0 0 0 1-1v-9a1 1 0 0 0-1-1z">
              </path>
          </g>
            <g 
              class="nc-icon-wrapper" fill="#111111">
              <title>other</title>
            <path 
              fill="#111111" d="M15,3h-2.5l-1.7-2.6C10.6,0.2,10.3,0,10,0H6C5.7,0,5.4,0.2,5.2,0.4L3.5,3H1C0.4,3,0,3.4,0,4v11 c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1V4C16,3.4,15.6,3,15,3z M14,14H2V5h2c0.3,0,0.6-0.2,0.8-0.4L6.5,2h2.9l1.7,2.6 C11.4,4.8,11.7,5,12,5h2V14z">
            </path> 
            <circle 
              data-color="color-2" cx="8" cy="9" r="3">      
            </circle>
          </g>
        </svg>
        

        basically, each <g> element represents an icon.
        I am reading the <g> element contents in C'tor and storing them into member variables ( in order to avoid reading again and again ).

        Then I am "loading" the icon based on the click event using the "QSvgRenderer".

        This works as expected, but is it the best practice or is there a better way I can acheive this ?

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 2 Jan 2020, 21:07 last edited by
          #4

          I understand your goal but what escapes me here is why you don't take advantage of QIcon's API. You should just have to assign each image of your SVG to the correct state on the icon and then it will be automatically be used by the button.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          R 1 Reply Last reply 3 Jan 2020, 01:56
          4
          • S SGaist
            2 Jan 2020, 21:07

            I understand your goal but what escapes me here is why you don't take advantage of QIcon's API. You should just have to assign each image of your SVG to the correct state on the icon and then it will be automatically be used by the button.

            R Offline
            R Offline
            Rizwan94
            wrote on 3 Jan 2020, 01:56 last edited by
            #5

            @SGaist
            Thanks for the reply.

            Do You mean to say something like this ?

            @
            toolButton = new QToolButton;
            toolButton->setCheckable(true);
            QIcon qIcon;
            qIcon.addFile(":/Icons/images/first.svg",QSize(32,32),QIcon::Normal,QIcon::On);
            qIcon.addFile(":/Icons/images/second.svg",QSize(32,32),QIcon::Normal,QIcon::Off);
            toolButton->setIcon(qIcon);
            @

            But here I need to have 2 seperate icons for on and off states.

            But What I am trying to do is that only single svg icon which has 2 states should be toggled on click ?
            Can that be done as per your above comment ?

            If my understanding of your above comment is wrong, would you please provide a minimal example ?

            1 Reply Last reply
            0
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on 3 Jan 2020, 09:00 last edited by
              #6

              @Rizwan94 said in Toggle svg icon on Button click - QT C++:

              But What I am trying to do is that only single svg icon which has 2 states should be toggled on click ?

              The Qt svg handle can not handle more than one image in a svg.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              R 1 Reply Last reply 3 Jan 2020, 16:24
              4
              • Christian EhrlicherC Christian Ehrlicher
                3 Jan 2020, 09:00

                @Rizwan94 said in Toggle svg icon on Button click - QT C++:

                But What I am trying to do is that only single svg icon which has 2 states should be toggled on click ?

                The Qt svg handle can not handle more than one image in a svg.

                R Offline
                R Offline
                Rizwan94
                wrote on 3 Jan 2020, 16:24 last edited by
                #7

                @Christian-Ehrlicher said in Toggle svg icon on Button click - QT C++:

                The Qt svg handle can not handle more than one image in a svg.

                Oh, fine then.
                I will go ahead with the approach suggested by @SGaist and make use of QIcon for toggling "each" svg icon.

                1 Reply Last reply
                1

                1/7

                30 Dec 2019, 16:54

                • Login

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