首页 > 解决方案 > 可点击的 SVG 图像运行方法

问题描述

我创建了一个需要交互的地图(火车)的 SVG 图像,当单击地图的一部分时,颜色会改变,并且会执行控制事物的方法(通过树莓派)。

将按钮连接到插槽很简单,我猜测我尝试过:

self.path.clicked.connect(self.some_func)

是否可以单击 SVG 元素并让它根据给定的方法执行方法,id就像单击按钮时一样?

这是一个MVCE:

测试.svg

<svg height="100" width="100">
    <circle id="elem1" cx="50" cy="50" r="40"/>
</svg> 

svg_widget.py

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtXml import *
from PyQt5.QtSvg import *
import sys

class svgWidget(QSvgWidget):
    def __init__(self, parent=None):
        super(QSvgWidget, self).__init__(parent)

        self.display = QTextEdit()
        self.doc = QDomDocument("doc")

        fName = QFile("test.svg")

        if not fName.open(QIODevice.ReadOnly):
            print("Cannot open the File")
            exit(-1)

        if not self.doc.setContent(fName):
            print("Cannot parse the content")
            fName.close()
            exit(-1)
        fName.close()

        roots = self.doc.elementsByTagName("svg")

        if roots.size() < 1:
            print("Cannot find root")
            exit(-1)

        self.root = roots.at(0).toElement()
        self.path = self.root.firstChild().toElement()

        self.load(self.doc.toByteArray())

        # self.path.clicked.connect(self.some_func)

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        QTimer.singleShot(2000, lambda: self.some_func()) 

    def some_func(self):
        print('setting fill')
        self.path.setAttribute("fill", "#44dd75")
        print('setting stroke')
        self.path.setAttribute("stroke", "#FF0000")
        print('setting stroke-width')
        self.path.setAttribute("stroke-width", "3")

        self.load(self.doc.toByteArray())

        self.execute_method()


    def execute_method(self):
        print('method executed')

if __name__ == "__main__":  
    app = QApplication(sys.argv)
    svgWidget = svgWidget()    
    svgWidget.show()                                                                                                                                                        
    sys.exit(app.exec_()) 

标签: pythonpyqtpyqt5qtsvg

解决方案


我通过我的一个朋友找到了解决方案。

它是在 Stackoverflow 上找到的(他认为)。

如果有人知道出处,请编辑并添加链接以获得信用。

测试.svg

<svg viewBox='0 0 108 95' 
xmlns='http://www.w3.org/2000/svg'>
<g transform='scale(0.1)'>
        <path id="p2" fill='blue' stroke='red' d='M249,699v43h211v-43h-64l-2,3l-2,4l-4,3c0,0-1,2-2,2h-4c-2,0-3,0-4,1c-1,1-3,1-3,
                        2l-3,4c0,1-1,2-2,2h-4c0,0-2,1-3,0l-3-1c-1,0-3-1-3-2c-1-1,0-2-1-3l-1-3c-1-1-2-1-3-1c-1,0-4,
                        0-4-1c0-2,0-3-1-4v-3v-3z'/>
    <path id="p3" fill='blue' d='M385,593c0,9-6,15-13,15c-7,0-13-6-13-15c0-8,12-39,14-39c1,0,12,31,12,39'/>
</g>
</svg>

svg_mouse.py

from PyQt5 import QtWidgets
from PyQt5.QtSvg import QGraphicsSvgItem, QSvgRenderer

class SvgItem(QGraphicsSvgItem):

    def __init__(self, id, renderer, parent=None):
        super().__init__(parent)
        self.id = id
        self.setSharedRenderer(renderer)
        self.setElementId(id)
        bounds = renderer.boundsOnElement(id)
        self.setPos(bounds.topLeft())
        #self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True) #horrible selection-box

    def mousePressEvent(self, event: 'QtWidgets.QGraphicsSceneMouseEvent'):
        print('svg item: ' + self.id + ' - mousePressEvent()')
        super().mousePressEvent(event)

    def mouseReleaseEvent(self, event: 'QtWidgets.QGraphicsSceneMouseEvent'):
        print('svg item: ' + self.id + ' - mouseReleaseEvent()')
        super().mouseReleaseEvent(event)

class SvgViewer(QtWidgets.QGraphicsView):
    def __init__(self, parent):
        super().__init__(parent)
        self._scene = QtWidgets.QGraphicsScene(self)
        self._renderer = QSvgRenderer()
        self.setScene(self._scene)

    def set_svg(self, data):
        self.resetTransform()
        self._scene.clear()
        self._renderer.load(data)
        item1 = SvgItem('p2', self._renderer)
        self._scene.addItem(item1)
        item2 = SvgItem('p3', self._renderer)
        self._scene.addItem(item2)

    def mousePressEvent(self, event: 'QtWidgets.QGraphicsSceneMouseEvent'):
        print('SvgViewer - mousePressEvent()')
        super().mousePressEvent(event)

    def mouseReleaseEvent(self, event: 'QtWidgets.QGraphicsSceneMouseEvent'):
        print('SvgViewer - mouseReleaseEvent()')
        super().mouseReleaseEvent(event)

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.viewer = SvgViewer(self)
        vb_layout = QtWidgets.QVBoxLayout(self)
        vb_layout.addWidget(self.viewer)
        img = b'''
                <svg viewBox='0 0 108 95' xmlns='http://www.w3.org/2000/svg'>
                    <g transform='scale(0.1)'>
                        <a href=""><path id="p2" d='M249,699v43h211v-43h-64l-2,3l-2,4l-4,3c0,0-1,2-2,2h-4c-2,0-3,0-4,1c-1,1-3,1-3,
                            2l-3,4c0,1-1,2-2,2h-4c0,0-2,1-3,0l-3-1c-1,0-3-1-3-2c-1-1,0-2-1-3l-1-3c-1-1-2-1-3-1c-1,0-4,
                            0-4-1c0-2,0-3-1-4v-3v-3z'/></a>
                        <path id="p3" d='M385,593c0,9-6,15-13,15c-7,0-13-6-13-15c0-8,12-39,14-39c1,0,12,31,12,39'/>
                    </g>
                </svg>'''
        self.viewer.set_svg(img)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 600, 400)
    window.show()
    sys.exit(app.exec_())

推荐阅读