QT使用程序加配置文件简单修改svg图片颜色

9 篇文章 3 订阅

参考文章

QT 动态更改SVG的颜色_octdream的专栏-CSDN博客   感谢博主

SVG 教程 | 菜鸟教程

背景

      公司目前使用qt制作一些widget界面的客户端程序(做的传统行业),没有使用qml,最近在开发界面的时候,发现要根据不同的现场要配置不同的样式,主要是配置颜色,有些控件上需要加载图片。不同的现场需要加载不同颜色的图片,现在使用的png,jpg这样的图片,图片是UI给的。但是有一个问题,同一张图为了应对不同的皮肤需要UI改成不同的颜色,比如五套皮肤,那么需要UI把一张图改成五种不同的颜色给我,我再去每套皮肤的qss中去设置加载的图片,很繁琐。

       最近了另一种图片格式svg,然后又了解到 svg css html 这三者搭配使用完成样式的调整,我萌生了一个想法。

       这里我也想说一下,虽然传统行业的软件程序不需要向互联网那样华丽,但是出几套皮肤,让客户眼前一新也是挺好,不同的现场搭配不同的主题皮肤,总比黑白灰这种好看。

想法

      首先,我梳理了一下目前更换皮肤的诟病所在,就是繁琐,就是麻烦,流程大概和下面这样

       这样操作,安装包会有重复的图片,就会变得臃肿,而且改样式也会麻烦,UI和程序员哪一个环节都需要重复劳动。

      而我的想法就是去掉重复,也许是尽可能的去掉重复,比如程序通过配置文件知道这几个svg需要修改成什么颜色,然后qss就不用改变了,因为一直加载的就是这几个svg。

      在了解svg之后,发现其实就是一个文本,我不是修改一个图片,我只是修改一个文本文件,我用qt、C++修改一个文本文件应该不难吧

构思

         按照上面的设想,我首先要解决json,这个需要考虑 qss 和 svg,然后决定数据结构是什么样的,那么首先看一下我到底要修改svg的什么数据。如下,按照目前的需求,我需要修改的是path中的fill属性,其他的不需要修改。

<?xml version='1.0' standalone='no'?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon" version="1.1" height="64.00px" width="64px">
 <path d="M933.3 227.3c-12.8-9.9-29.3-15.3-46.4-15.3H818v-30.7c0-65.6-56.6-119-126.1-119h-359c-69.5 0-126.1 53.4-126.1 119V212h-68.9c-17.2 0-33.7 5.4-46.4 15.3-15.3 11.8-24.1 29.1-24.1 47.4 0 56.4 17.1 109.7 48.3 150.2 15.9 20.6 34.5 36.9 55.5 48.4 11.5 6.3 23.4 11 35.6 14.2v24.3c0 39.2 8.2 77.2 24.4 112.9 15.5 34.4 37.7 65.2 66 91.6 49 45.8 111.6 74.1 179.2 81.5v87.4H320.1c-19.9 0-36 16.1-36 36s16.1 36 36 36h383.3c19.9 0 36-16.1 36-36s-16.1-36-36-36h-155v-87.4c67.6-7.4 130.2-35.7 179.2-81.5 28.2-26.4 50.4-57.2 66-91.6C809.8 589 818 551.1 818 512v-24.5c12.2-3.1 24.1-7.8 35.6-14.2 21-11.5 39.7-27.8 55.5-48.4 31.1-40.5 48.3-93.8 48.3-150.2 0-18.3-8.8-35.5-24.1-47.4zM172.7 381c-19.9-25.8-31.5-60-33.1-97h67.2v126.7c-12.4-6.6-24-16.6-34.1-29.7z m339.7 346.8c-128.8 0-233.6-96.9-233.6-216V181.3c0-25.9 24.3-47 54.1-47h358.9c29.8 0 54.1 21.1 54.1 47v330.5c0 119.1-104.7 216-233.5 216zM852 381c-10.1 13.1-21.7 23.1-34.1 29.7V284h67.2c-1.6 37-13.2 71.1-33.1 97z" fill="#ff0000"/>
 <path d="M512.437 514.688l89.41 39.376c4.912 2.155 10.218-1.763 9.628-7.053l-10.611-101.085 58.755-66.802c3.34-3.918 1.572-9.795-3.34-11.166l-85.48-22.92-52.86-85.806c-2.751-4.31-9.04-4.31-11.79 0l-52.86 85.61-85.48 22.92c-4.913 1.371-6.878 7.444-3.34 11.166l58.754 66.802-10.611 101.085c-0.59 5.29 4.913 9.208 9.629 7.053l89.41-39.376 0.786 0.196z" fill="#ff0000"/>
</svg>

         但是正如你所看到的,有一个svg中不会只有一个path,上面这个就有两个path,那就可以有更多,同理,矩形 <rect>  圆形 <circle>  椭圆 <ellipse>   线 <line>  折线 <polyline> ,这样就要考虑有多个标签相同的情况,所以json里面需要数组,而且svg本身需要小改一下,那就是增加一个id标签就像下面这样,增加id只是为方便区分相同标签,对svg的显示没有影响。

<?xml version='1.0' standalone='no'?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon" version="1.1" height="64.00px" width="64px">
 <path id="1" d="M933.3 227.3c-12.8-9.9-29.3-15.3-46.4-15.3H818v-30.7c0-65.6-56.6-119-126.1-119h-359c-69.5 0-126.1 53.4-126.1 119V212h-68.9c-17.2 0-33.7 5.4-46.4 15.3-15.3 11.8-24.1 29.1-24.1 47.4 0 56.4 17.1 109.7 48.3 150.2 15.9 20.6 34.5 36.9 55.5 48.4 11.5 6.3 23.4 11 35.6 14.2v24.3c0 39.2 8.2 77.2 24.4 112.9 15.5 34.4 37.7 65.2 66 91.6 49 45.8 111.6 74.1 179.2 81.5v87.4H320.1c-19.9 0-36 16.1-36 36s16.1 36 36 36h383.3c19.9 0 36-16.1 36-36s-16.1-36-36-36h-155v-87.4c67.6-7.4 130.2-35.7 179.2-81.5 28.2-26.4 50.4-57.2 66-91.6C809.8 589 818 551.1 818 512v-24.5c12.2-3.1 24.1-7.8 35.6-14.2 21-11.5 39.7-27.8 55.5-48.4 31.1-40.5 48.3-93.8 48.3-150.2 0-18.3-8.8-35.5-24.1-47.4zM172.7 381c-19.9-25.8-31.5-60-33.1-97h67.2v126.7c-12.4-6.6-24-16.6-34.1-29.7z m339.7 346.8c-128.8 0-233.6-96.9-233.6-216V181.3c0-25.9 24.3-47 54.1-47h358.9c29.8 0 54.1 21.1 54.1 47v330.5c0 119.1-104.7 216-233.5 216zM852 381c-10.1 13.1-21.7 23.1-34.1 29.7V284h67.2c-1.6 37-13.2 71.1-33.1 97z" fill="#ff0000"  />
 <path id="2" d="M512.437 514.688l89.41 39.376c4.912 2.155 10.218-1.763 9.628-7.053l-10.611-101.085 58.755-66.802c3.34-3.918 1.572-9.795-3.34-11.166l-85.48-22.92-52.86-85.806c-2.751-4.31-9.04-4.31-11.79 0l-52.86 85.61-85.48 22.92c-4.913 1.371-6.878 7.444-3.34 11.166l58.754 66.802-10.611 101.085c-0.59 5.29 4.913 9.208 9.629 7.053l89.41-39.376 0.786 0.196z" fill="#ff0000"  />
</svg>

       看完了svg接下来就要考虑qss,qss需要去加载不同名称的图片,不同的图片在不同应用场景的样式是不同的,所以json中还要有能区分图片名称的信息,这样可以加一个图片名称对象,而且一套皮肤主题就会对应一个qss文件,那么json中也要体现皮肤主题的信息,这样可以加一个皮肤主题名称的对象。

       json数据构思好了,接下来就是想怎么去读取编辑svg文件本身了,这里可以直接使用qt自己的库,#include <QDomElement>     #include <QDomDocument>,QT += core gui svg xml,大概就这些,有兴趣的小伙伴可以深入研究一下

XML DOM | 菜鸟教程

      qss加载svg和加载普通的png,jpg差不多,

      程序加载qss就不再细说。

代码

       在这里,我把主要的几个文件内容展示出来,欢迎各位高手的斧正,如果觉得对你有帮助,那我会很有成就感。

//解析json内容的函数
void DealJson(QString _qstrJson,QString _qstrSkin, QString _qstrImagePath)
{
    //读取json配置文件
    QFile fileJson(_qstrJson);
    fileJson.open(QIODevice::ReadOnly);
    QJsonDocument jsondoc = QJsonDocument::fromJson(fileJson.readAll());  //注意这里是怎么赋值的
    QJsonObject obj = jsondoc.object(); //第一层

    if(obj.contains(_qstrSkin))
    {
        QJsonObject objFileName = obj[_qstrSkin].toObject(); //第二层
        QStringList listFileName = objFileName.keys();        //这里获取的都是文件名称
        for(int i = 0; i < listFileName.size(); ++i)
        {
           QString qstrFileName = listFileName[i];
           QString qstrFilePath  = _qstrImagePath + qstrFileName+".svg";  //配置要修改的svg文件路径
           QFile fileSvg(qstrFilePath);
           fileSvg.open(QIODevice::ReadOnly);
           QByteArray baData = fileSvg.readAll();
           fileSvg.close();
           QDomDocument doc;
           doc.setContent(baData);
           QDomElement element = doc.documentElement();

           QJsonObject objLabel = objFileName[qstrFileName].toObject(); //第三层

           QStringList listLabel = objLabel.keys();                     //这里获取的是标签名
           for(int j = 0; j < listLabel.size(); ++j)
           {
               QString qstrLabel = listLabel[j];
               if(objLabel[qstrLabel].isArray()) //如果是数组
               {
                   QJsonArray arrayAttribute = objLabel[qstrLabel].toArray(); //第四层
                   for(int q = 0; q < arrayAttribute.size(); ++q)
                   {
                       QJsonObject objAttribute = arrayAttribute[q].toObject();        //第五层
                       QStringList listAttribute = objAttribute.keys();

                       QString qstrId = "";
                       if(objAttribute.contains("id"))
                       {
                           qstrId = objAttribute["id"].toString();
                       }
                       for(int p = 0; p < listAttribute.size(); ++p)
                       {
                            QString key = listAttribute[p];
                            QString value = objAttribute[key].toString();
                            SetAttrRecur(element, qstrLabel, qstrId, key, value);
                            fileSvg.setFileName(qstrFilePath);
                            fileSvg.open(QIODevice::WriteOnly);
                            fileSvg.write(doc.toByteArray());
                            fileSvg.close();
                       }
                   }
               }
               else if(objLabel[qstrLabel].isObject()) //如果是对象
               {
                   QJsonObject objAttribute = objLabel[qstrLabel].toObject();
                   QStringList listAttribute = objAttribute.keys(); //这里获取的是属性名称
                   for(int k = 0; k < listAttribute.size(); ++k)
                   {
                       QString key = listAttribute[k];
                       QString value = objAttribute[key].toString();
                       SetAttrRecur(element, qstrLabel,"", key, value);
                       fileSvg.setFileName(qstrFilePath);
                       fileSvg.open(QIODevice::WriteOnly);
                       fileSvg.write(doc.toByteArray());
                       fileSvg.close();
                   }
               }
           }
        }
    }
}


//这是借鉴其他博主的作用是修改svg内容的
void SetAttrRecur(QDomElement &elem, QString strtagname, QString id ,QString strattr, QString strattrval)
{
    if (elem.tagName().compare(strtagname) == 0) //当找到了要修改的对象 就设置属性
    {
       if(id != "" && elem.attribute("id") == id)
       {
           elem.setAttribute(strattr, strattrval);
       }
       else if(id == "")
       {
           elem.setAttribute(strattr, strattrval);
       }
    }

    //循环查找
    for (int i = 0; i < elem.childNodes().count(); i++)
    {
        if (!elem.childNodes().at(i).isElement()) //如果不是元素
        {
            continue;
        }

        QDomElement element = elem.childNodes().at(i).toElement();
        SetAttrRecur(element, strtagname, id, strattr, strattrval);
    }
}

{
    "skinOne":   //皮肤主题
    {
        "guanliyuangongju":   //图片名称
        {
            "path":{"fill":"#ff0000"}  //标签
        },
        "shangchuan-chenggong":
        {
            "path":{"fill":"#ff0000"}
        },
        "shebeiguanli":
        {
            "path":{"fill":"#ff0000"}
        },
        "shipinjiankong":
        {
            "path":
            [
             {"id":"1","fill":"#ff0000"},
             {"id":"2","fill":"#ff0000"}
            ]
        },
        "yuanguanli":
        {
            "path":{"fill":"#ff0000"}
        },
        "banbenguanli":
        {
            "path":{"fill":"#ff0000"}      
        },
        "baojing":
        {
            "path":{"fill":"#ff0000"}    
        },
        "baojingchaxun":
        {
            "path":{"fill":"#ff0000"} 
        },
        "bisaiguanli":
        {
            "path":{"fill":"#ff0000"} 
        }
    },
    "skinTwo":
    {
        "guanliyuangongju":
        {
            "path":{"fill":"#ffff00"}
        },
        "shangchuan-chenggong":
        {
            "path":{"fill":"#ffff00"}
        },
        "shebeiguanli":
        {
            "path":{"fill":"#ffff00"}
        },
        "shipinjiankong":
        {
            "path":
            [
             {"id":"1","fill":"#ffff00"},
             {"id":"2","fill":"#ffff00"}
            ]
        },
        "yuanguanli":
        {
            "path":{"fill":"#ffff00"}
        },
        "banbenguanli":
        {
            "path":{"fill":"#ffff00"}      
        },
        "baojing":
        {
            "path":{"fill":"#ffff00"}    
        },
        "baojingchaxun":
        {
            "path":{"fill":"#ffff00"} 
        },
        "bisaiguanli":
        {
            "path":{"fill":"#ffff00"} 
        }
    },
    "skinThree":
    {
        "guanliyuangongju":
        {
            "path":{"fill":"#ff00ff"}
        },
        "shangchuan-chenggong":
        {
            "path":{"fill":"#ff00ff"}
        },
        "shebeiguanli":
        {
            "path":{"fill":"#ff00ff"}
        },
        "shipinjiankong":
        {
            "path":
            [
             {"id":"1","fill":"#ff00ff"},
             {"id":"2","fill":"#ff00ff"}
            ]
        },
        "yuanguanli":
        {
            "path":{"fill":"#ff00ff"}
        },
        "banbenguanli":
        {
            "path":{"fill":"#ff00ff"}      
        },
        "baojing":
        {
            "path":{"fill":"#ff00ff"}    
        },
        "baojingchaxun":
        {
            "path":{"fill":"#ff00ff"} 
        },
        "bisaiguanli":
        {
            "path":{"fill":"#ff00ff"} 
        }
    }
}

最终效果

         通过json的配置,只需要一组svg就可以实现变色效果

总结

(1)  现在这个还没有在实际中应用过,只是自己记录自己探索的一个过程

(2)  现在这种方法的缺点较多,如会修改svg数据,配置json文档比较繁琐,当然还可能有一些实际的应用情况没有考虑到

(3)  现在的方法除了可以修改颜色外,svg中的其他属性也可以修改

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值