QT 动态更改SVG的颜色

好久没有写QT了, 前阵子写的控件都没时间整理和改进,一直有个想法就是想将里面的PNG改成SVG,因为png用QPixmap绘制出来的是位图,一放大就失真,之前研究的将PNG颜色更改就白忙活了,代码如下
void GaugeColorScheme::setCenterImageColor(QImage &image,QColor &color)
{
    image  = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied,Qt::NoFormatConversion);
    int bmpWidth = image.width();
    int bmpHeight = image.height();
    for(int i=0;i< bmpWidth;++i)
    {
        for(int j=0;j<bmpHeight;++j)
        {
            //将灰色(0~255)全部替换成设定的颜色,全透明的不替换
            QColor tempColor = image.pixelColor(i,j);
            if(tempColor.alpha() != 0)
            {
                color.setAlpha(tempColor.alpha());
                image.setPixelColor(i,j,color);
            }
        }
    }
}


QImage image = centerPixImg.toImage();
    setCenterImageColor(image,centerImgColor);

    painter->drawImage(-image.width()/2,-image.height()/2, image);

以上代码是将png颜色替换的方法,给需要的朋友,在这里我没有用这种方法了,为了绘制出来的图标不失真,我想到了svg。

svg图标格式其实本质上是一个xml文件,我本想直接使用QT封装的SVG操作类,无耐没有找到好的方法,我想既然是xml文件,那就直接用QT的xml操作类,对文件的相关属性进行更改就可以了,我找了一个svg文件打开并研究里面的内容,在这里我给大家推荐一个图标下载库,也许有很多朋友都知道这个库,那就是“阿里图标库”,里面有大量的免费的图标下载。


以上是我打开一个svg图标的内容,是不是很简单,在根为svg,在里面描述了图标的大小等信息,在有个子标签path,描述了图标的填充颜色以及绘制路径等信息,我们所需要的就是这个填充颜色,我们只要更改它就可以了,所以我设计了以下一个函数。

void GaugeStation::SetAttrRecur(QDomElement &elem, QString strtagname, QString strattr, QString strattrval)
{
    // if it has the tagname then overwritte desired attribute
    if (elem.tagName().compare(strtagname) == 0)
    {
        elem.setAttribute(strattr, strattrval);
    }
    // loop all children
    for (int i = 0; i < elem.childNodes().count(); i++)
    {
        if (!elem.childNodes().at(i).isElement())
        {
            continue;
        }
        SetAttrRecur(elem.childNodes().at(i).toElement(), strtagname, strattr, strattrval);
    }
} 

elem:DOM树的一个元素句柄   strtagname:标签名  strattr:属性名    strattrval:属性值

由以上函数可以看出,我是用的DOM的方式对svg进行解析和修改的,在函数中我用了一个递归的方式对svg中的数据进行更改。具体大家可以自己去深入研究一下QT对xml的操作方法。接下来大家看我的调用。

void GaugeStation::drawCenterPixMap(QPainter *painter)
{
    painter->save();
    int width_svg = 50;
    int height_svg = 50;

    QFile file( centerSvgPath );
    file.open(QIODevice::ReadOnly);
    QByteArray baData = file.readAll();
    // load svg contents to xml document and edit contents
    QDomDocument doc;
    doc.setContent(baData);

    file.close();
    // recurivelly change color

    if(innerCurrValue >= 0)
    {
        //正角度
        SetAttrRecur(doc.documentElement(), "path", "fill", rgb2HexStr(centerPixMapNegativeColor));
    }
    else
    {
        //负角度
        SetAttrRecur(doc.documentElement(), "path", "fill", rgb2HexStr(centerPixMapPositiveColor));
    }

    QSvgRenderer m_svgRender(doc.toByteArray());
    m_svgRender.render(painter ,QRectF(-width_svg,-height_svg/2,width_svg ,height_svg));
    painter->restore();
}

在使用这QT操作xml,以及svg时,要加入 QT += xml svg

并包含头文件:#include<QDomDocument> #include<QSvgRenderer> #include<QFile>

我们用QFile将文件打开并获取内容到QDomDocument然后调用函数,更改path标签下的fill属性,更改后将内容导入QSvgRenderer,利用painter将内容绘制出来。

另外在svg中描述颜色好像只能是 :red,blue,black。。。等,以及颜色的16进制字符串格式,所以我写了一个QColor 转16进制字符串的函数,不知道QT中有没有其它好用的方法不用自己转换的,我们方法如下:

QString GaugeStation::rgb2HexStr(const QColor &color)
{
    QString redStr = QString("%1").arg(color.red(), 2, 16, QChar('0'));
    QString greenStr = QString("%1").arg(color.green(), 2, 16, QChar('0'));
    QString blueStr = QString("%1").arg(color.blue(), 2, 16, QChar('0'));
    QString key = "#" + redStr + greenStr + blueStr;
    return key;
}

方法介绍完毕,如里大家有更好的方法,可以告诉我,欢迎大家来指正,谢谢!

猜你喜欢

转载自blog.csdn.net/octdream/article/details/79492778