PyQt5动态更改SVG颜色

PyQt5动态更改SVG颜色

qt自带的库没有发现可以动态更改SVG图片颜色的,也有可能qt自带但是没发现,反正我没发现,所以在这里分享一个

lxml

SVG本质上还是一种xml文本,因此可以使用lxml库来解析。
lxml一个解析库,lxml提供了对xml,HTML,SVG等标签语言的解析。

有人可能觉得bs4也可以解析SVG,事实上bs4只能查看标签的属性或文本。无法修改,因此使用lxml。

SVG虽然和xml与HTML本质是一个东西,但是使用的定位方式却是不同的。
SVG是有一个<svg></svg>与多个<path></path>组成,因此直接定位SVG标签与path标签就好。svg标签设置图片的大小与ID,path标签设置内容与颜色。

注: svg无法通过普通的xpath定位,需要改稍微一下定位方式。
获取所有元素://*
获取svg标签://*[name()="svg"]
获取svg标签下的所有path标签://*[name()="svg"]//*[name()="path"]

知道这个后就可以直接用了

from lxml import etree
from lxml.etree import _Element

filepath = '经营计划.svg'
with open(filepath, mode='r', encoding='utf-8') as fp:
    svg_data = fp.read()
svg_tree = etree.fromstring(svg_data, etree.XMLParser(remove_blank_text=True))  # type: _Element
print(svg_tree.xpath('//*[name()="svg"]//*[name()="path"]'))

# 输出:
# [<Element {http://www.w3.org/2000/svg}path at 0x23b385e9a40>, <Element {http://www.w3.org/2000/svg}path at 0x23b385e9a80>, <Element {http://www.w3.org/2000/svg}path at 0x23b385e9ac0>]

为了方便稍微封装一下

class SVGParser:
    """
    SVG解析器
    """
    filepath = None
    svg_tree = None

    def __init__(self, filepath):
        if not Path(filepath).is_file:
            raise FileNotFoundError(f'没有此文件: {filepath}')
        with open(filepath, mode='r', encoding='utf-8') as fp:
            self.svg_data = fp.read()
        self.svg_tree = etree.fromstring(self.svg_data, etree.XMLParser(remove_blank_text=True))  # type: _Element

    def get_all_element(self):
        """
        获取所有元素
        """
        return self.svg_tree.xpath('//*')

    def get_tag_element(self, tag_name: str, **kwargs):
        """
        获取指定元素
        """
        xpath_str = f'//*[name()="' + tag_name + '"'
        items = kwargs.items()

        for key, value in items:
            key = key.replace('_', '-')
            xpath_str += ' and @' + key + '="' + value + '"'
        xpath_str = xpath_str + ']'
        elements = self.svg_tree.xpath(xpath_str)  # type: _Element
        if len(elements) <= 1:
            element = elements[0]  # type: _Element
            return element
        return elements

    def toString(self):
        """
        将dict转为svg文本
        """
        return etree.tostring(self.svg_tree, pretty_print=True)

QSvgWidget显示svg图片

使用QSvgWidget显示修改后的数据

import sys
from pathlib import Path

from PyQt5.Qt import *
from lxml import etree
from lxml.etree import _Element


class SVGParser:
    """
    SVG解析器
    """
    filepath = None
    svg_tree = None

    def __init__(self, filepath):
        if not Path(filepath).is_file:
            raise FileNotFoundError(f'没有此文件: {filepath}')
        with open(filepath, mode='r', encoding='utf-8') as fp:
            self.svg_data = fp.read()
        self.svg_tree = etree.fromstring(self.svg_data, etree.XMLParser(remove_blank_text=True))  # type: _Element

    def get_all_element(self):
        """
        获取所有元素
        """
        return self.svg_tree.xpath('//*')

    def get_tag_element(self, tag_name: str, **kwargs):
        """
        获取指定元素
        """
        xpath_str = f'//*[name()="' + tag_name + '"'
        items = kwargs.items()

        for key, value in items:
            key = key.replace('_', '-')
            xpath_str += ' and @' + key + '="' + value + '"'
        xpath_str = xpath_str + ']'
        elements = self.svg_tree.xpath(xpath_str)  # type: _Element
        if len(elements) <= 1:
            element = elements[0]  # type: _Element
            return element
        return elements

    def toString(self):
        """
        将dict转为svg文本
        """
        return etree.tostring(self.svg_tree, pretty_print=True)


class SvgWidget(QSvgWidget):
    def __init__(
            self,
            filepath, parent=None, *,
            default_color: str = '#000000',
            hover_color: str = '#ff3d00',
            press_color: str = '#6c216d'
    ):
        super(SvgWidget, self).__init__(parent)
        # 初始化颜色
        self.default_color = default_color  # 默认颜色
        self.hover_color = hover_color  # 鼠标经过颜色
        self.press_color = press_color  # 鼠标点击颜色

        self.isHover = False  # 鼠标是否经过
        self.isPress = False  # 鼠标是否点击

        self.svg_data = SVGParser(filepath)
        self.svg_tag = self.svg_data.get_tag_element('svg')
        self.path_tags = self.svg_data.get_tag_element('path')

        self.setSvgColor(self.default_color, self.hover_color, self.press_color)
        self.initSvgData(self.default_color)

    def initSvgData(self, color: str):
        # 初始化svg数据,并进行显示
        for tag in self.path_tags:
            tag.set('fill', color)
        self.renderer().load(QByteArray(self.svg_data.toString()))
        self.update()

    def setSvgColor(self, default_color: str, hover_color: str, press_color: str):
        """
        svg图片颜色
        二进制颜色:#a0610e;
        英文颜色:red
        """
        self.default_color = default_color
        self.hover_color = hover_color
        self.press_color = press_color
        self.update()

    def resizeEvent(self, evt: QResizeEvent) -> None:
        """
        窗口大小事件
        """
        self.svg_tag.set('width', str(evt.size().width()))
        self.svg_tag.set('height', str(evt.size().height()))

    def enterEvent(self, a0: QEvent) -> None:
        """
        鼠标进入事件
        """
        self.isHover = True
        if self.isHover:
            self.initSvgData(self.hover_color)

    def leaveEvent(self, a0: QEvent) -> None:
        """
        鼠标离开事件
        """
        self.isHover = False
        if self.isHover is False:
            self.initSvgData(self.default_color)

    def mousePressEvent(self, a0: QMouseEvent) -> None:
        """
        鼠标点击事件
        """
        self.isPress = True
        if self.isPress and self.isHover:
            self.initSvgData(self.press_color)

    def mouseReleaseEvent(self, a0: QMouseEvent) -> None:
        """
        鼠标松开事件
        """
        self.isPress = False
        if self.isPress is False:
            self.initSvgData(self.hover_color)


if __name__ == '__main__':
    QApplication.setHighDpiScaleFactorRoundingPolicy(
        Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
    )
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
    app = QApplication(sys.argv)
    win = SvgWidget('经营计划.svg')
    win.show()
    sys.exit(app.exec_())

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值