ItemClipsToShape QGraphicsSVGItem

问题描述 投票:0回答:1

以下标志不执行其意图并剪切形状。而是创建一个矩形选择。

self.setFlag(self.ItemClipsToShape)

enter image description here enter image description here

如何使选择夹适应形状?

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_())
python svg pyqt pyqt5 qgraphicssvgitem
1个回答
1
投票

我认为QGraphicsSvgItem使用边界矩形为其形状。

一种可能的[[hacky但有效的解决方案是执行QGraphicsPixmapItem所做的事情,即获取掩码并使用alpha区域返回元素的shape()

请注意,我没有设置ItemClipsToShape标志,因为不需要它。我还基于Qt implementation实现了正确的选择轮廓。

clipping and selection

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) # create an image based on the item size img = QtGui.QImage(bounds.size().toSize(), QtGui.QImage.Format_ARGB32) # clear its buffer (this is important!) img.fill(QtCore.Qt.transparent) # create a qpainter and ask the renderer to render it qp = QtGui.QPainter(img) renderer.render(qp, id) qp.end() # create the mask by adding a QRegion based on it mask = img.createAlphaMask() shape = QtGui.QPainterPath() shape.addRegion(QtGui.QRegion(QtGui.QBitmap.fromImage(mask))) # a QBitmap based region can be unnecessarily complex, let's # simplify it self._shape = shape.simplified() def shape(self): return self._shape def paint(self, qp, option, widget): # keep track of the selected state and call the base painting # implementation without it selected = option.state & QtWidgets.QStyle.State_Selected option.state &= ~QtWidgets.QStyle.State_Selected super().paint(qp, option, widget) if selected: # draw the selection based on the shape, using the right # amount of contrast with the background fgcolor = option.palette.windowText().color() bgcolor = QtGui.QColor( 0 if fgcolor.red() > 127 else 255, 0 if fgcolor.green() > 127 else 255, 0 if fgcolor.blue() > 127 else 255, ) qp.setPen(QtGui.QPen(bgcolor, 0, QtCore.Qt.SolidLine)) qp.setBrush(QtCore.Qt.NoBrush) qp.drawPath(self._shape) qp.setPen(QtGui.QPen(option.palette.windowText(), 0, QtCore.Qt.DashLine)) qp.setBrush(QtCore.Qt.NoBrush) qp.drawPath(self._shape)

© www.soinside.com 2019 - 2024. All rights reserved.