The following flag does not do what it is meant to and clip the shape. Instead it creates a rectangular selection.
self.setFlag(self.ItemClipsToShape)
How can I make the selection clip to the shape?
test.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_())


I think that QGraphicsSvgItem uses the bounds rectangle for its shape.
A possible hacky but effective solution is to do what QGraphicsPixmapItem does, that is to get the mask and use the alpha region for to return the
shape()of the element.Note that I'm not setting the ItemClipsToShape flags, because there's no need for it.
I also implemented the correct selection outline, based on the Qt implementation.