【发布时间】:2019-11-28 14:23:16
【问题描述】:
我创建了一个需要交互的地图(火车)的 SVG 图像,当点击地图的一部分时,颜色会发生变化,并且会执行控制事物的方法(通过树莓派)。
将按钮连接到插槽很简单,我猜测一下:
self.path.clicked.connect(self.some_func)
是否可以单击 SVG 元素并让它根据给定的id 执行方法,就像单击按钮时一样?
这是一个 MVCE:
test.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_())
【问题讨论】:
-
不,没有那样的东西。如果想使用 SVG,你必须自己从 scatch 实现一切。使用 Qt 的 Graphics View Framework 创建地图会更好。
-
实际上,您可以从 SVG 文档(使用 QSvgRenderer)中提取单个命名元素,然后独立绘制它们(作为可点击/可选择的项目,可选择在 QGraphicsView 或类似中)。您也不需要手动解析 SVG(作为 XML)。或者,获取每个元素的边界并手动创建 SVG 图形项的“可点击区域”(例如通过监听鼠标事件)。你的 SVG 源是否支持这样的东西(IOW,它有命名元素)吗?
-
是的,svg 中的每个元素都可以使用
id="elem_name"。是的,这正是我所希望的,让我能够将元素 ID 分配给鼠标单击和悬停事件。我已经更新了 svg 以反映这一点。