QGraphicsSvgItem事件传播(交互式svg查看器)

2024-09-27 23:18:16 发布

您现在位置:Python中文网/ 问答频道 /正文

目前我正在构建一个最简单的svg查看器,在这个查看器中,用户应该能够选择所绘制图形的子项。在

使用

具有共享渲染器的QGraphicsSvgItem。然后将项目添加到图形视图中。在

不,棘手的部分来了。我需要单选项目(通过点击他们)和一个橡皮筋多选。在

我正在努力与鼠标传播的事件。文件说,所有的事件都是从孩子传给父母的。 换句话说,通过单击一个SvgItem,我假设项目的事件处理程序是在查看器的处理程序之前触发的。事实并非如此。在

我创建了一个应用程序示例:

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)

    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)'>
                        <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'/>
                        <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_())

单击显示的svg项将生成以下控制台输出:

^{pr2}$

我的目标是:

  1. 用户单击一个项目->;此项目已被选中(接受事件,并且不创建选择矩形)
  2. 用户单击空白区域并开始移动鼠标->;将显示一个选择矩形

当鼠标左键单击在可见项上方时,我如何跳过查看器中的事件处理(基于手动位置检查的优先无任何逻辑)?在

任何建议都是非常受欢迎的!在


Tags: 项目svgselfeventidinitdef事件

热门问题