首页 > 解决方案 > 如何在按钮单击时切换 svg 图标 - 使用 QT C++

问题描述

我对 svg + QT 概念比较陌生。我创建了一个具有 2 个状态的 svg 图标。我想将此 svg 图标添加到 QPushButton。单击按钮时,应切换图标(显示其他状态)。

谁能告诉我如何在 QT 中做到这一点?QT 与 C++!

编辑:

我尝试使用 svg 图标并在单击按钮时切换它。我已经实现了预期的行为,但我想知道这是否是正确的做法。

我在下面粘贴代码文件和 svg 图标内容


我已经尝试过使用 QSvgRenderer 和 QIcon。我已经实现了我一直在寻找的东西。

但我不确定这是否应该这样做。请看一下,让我知道这是否是首选方式。

我从https://nucleoapp.com/tool/icon-transition创建了一个 svg 图标(使用 2 个其他 svg 图标) svg 图标嵌入了 2 个 svg 图标。我现在的目标是在单击按钮时切换图标。

在下面查看我的文件

    #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

.cpp 文件

#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;
    }
}

svg 文件的内容

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

基本上,每个“g”元素代表一个图标。我正在读取 C'tor 中的每个 g 元素内容并将它们存储到成员变量中(以避免一次又一次地读取)。

然后我使用“QSvgRenderer”根据点击事件“加载”图标。

这可以按预期工作,但这是最佳实践还是有更好的方法可以实现这一目标?

标签: qtsvg

解决方案


推荐阅读