проблема с изменением размера svg-изображений в pyqt5 с векторным эффектом - PullRequest
1 голос
/ 07 мая 2020

У меня QGraphicsSvgItem на QGraphicsScene . Я пытаюсь изменить его размер с помощью элементов захвата (строки), которые расположены в ограничивающем прямоугольнике QGraphicsSvgItem . В файле test.svg я установил для свойства векторного эффекта значение non-scaling-stroke.
когда я изменяю его размер, растягивая элемент захвата, он создает пустое пространство между ограничивающим прямоугольником и контуром изображения svg. Вот файл test.svg, см. Стиль последнего тега <g>.

ниже код

import sys
from PyQt5.QtSvg import QGraphicsSvgItem, QSvgRenderer
from PyQt5.QtWidgets import QLineEdit, QGraphicsItem, QApplication, QMainWindow, QGraphicsScene, QGraphicsView, \
    QGraphicsPathItem
from PyQt5.QtGui import QPen, QColor, QCursor, QPainterPath
from PyQt5.QtCore import Qt, QRectF, QPointF



class SizeGripItem(QGraphicsPathItem):
    def __init__(self, annotation_item, index, direction=Qt.Horizontal, parent=None):
        super(QGraphicsPathItem, self).__init__(parent=parent)
        self.width = self.height = 0
        if direction is Qt.Horizontal:
            self.height = annotation_item.boundingRect().height()
        else:
            self.width = annotation_item.boundingRect().width()

        path = QPainterPath()
        path.addRect(QRectF(0, 0, self.width, self.height))
        self.m_annotation_item = annotation_item
        self._direction = direction
        self.m_index = index
        self.setPath(path)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.setAcceptHoverEvents(True)
        self.setPen(QPen(QColor("black"), 2))
        self.setBrush(QColor("red"))
        self.setZValue(2)


    @property
    def direction(self):
        return self._direction

    def update_path(self):
        if self._direction is Qt.Horizontal:
            self.height = self.m_annotation_item.boundingRect().height()
        else:
            self.width = self.m_annotation_item.boundingRect().width()
        path = QPainterPath()
        path.addRect(QRectF(0, 0, self.width, self.height))
        self.setPath(path)

    def update_position(self):
        """updates grip items
        """
        self.update_path()
        pos = self.m_annotation_item.mapToScene(self.point(self.m_index))
        x = self.m_annotation_item.boundingRect().x()
        y = self.m_annotation_item.boundingRect().y()
        pos.setX(pos.x() + x)
        pos.setY(pos.y() + y)
        self.setEnabled(False)
        self.setPos(pos)
        self.setEnabled(True)

    def point(self, index):
        """
        yields a list of positions of grip items in a node item
        """
        x = self.m_annotation_item.boundingRect().width()
        y = self.m_annotation_item.boundingRect().height()
        if 0 <= index < 4:
            return [
                QPointF(0, 0),
                QPointF(0, 0),
                QPointF(0, y),
                QPointF(x, 0)
            ][index]

    def hoverEnterEvent(self, event):
        if self._direction == Qt.Horizontal:
            self.setCursor(QCursor(Qt.SizeHorCursor))
        else:
            self.setCursor(QCursor(Qt.SizeVerCursor))
        super(SizeGripItem, self).hoverEnterEvent(event)

    def hoverLeaveEvent(self, event):
        self.setCursor(QCursor(Qt.ArrowCursor))
        super(SizeGripItem, self).hoverLeaveEvent(event)

    def itemChange(self, change, value):
        """
        Moves position of grip item on resize or reference circle's position change
        """
        if change == QGraphicsItem.ItemPositionChange and self.isEnabled():
            p = QPointF(self.pos())
            if self.direction == Qt.Horizontal:
                p.setX(value.x())
            elif self.direction == Qt.Vertical:
                p.setY(value.y())
            self.m_annotation_item.resize(self.m_index, p)
            return p
        return super(SizeGripItem, self).itemChange(change, value)

class NodeItem(QGraphicsSvgItem):

    def __init__(self, parent=None):
        QGraphicsSvgItem.__init__(self, parent)
        self.m_renderer = QSvgRenderer("test.svg")
        self.setSharedRenderer(self.m_renderer)
        self.rect = QRectF(0, 0, 150, 300)

        self.setFlags(QGraphicsSvgItem.ItemIsMovable |
                      QGraphicsSvgItem.ItemIsSelectable |
                      QGraphicsSvgItem.ItemSendsGeometryChanges)

        self.lineGripItems = []
        self.sizeGripItems = []

    def boundingRect(self):
        return self.rect

    def paint(self, painter, option, widget):
            self.m_renderer.render(painter, self.boundingRect())

    def resize(self, i, p):
        """Move grip item with changing rect of node item
        """
        x = self.boundingRect().x()
        y = self.boundingRect().y()
        width = self.boundingRect().width()
        height = self.boundingRect().height()
        p_new = self.sizeGripItems[i].pos()
        self.prepareGeometryChange()

        if i == 0 or i == 1:
            self.rect = QRectF(x + p.x() - p_new.x(), y + p.y() - p_new.y(), width - p.x() + p_new.x(),
                               height - p.y() + p_new.y())

        if i == 2 or i == 3:
            self.rect = QRectF(x, y, width + p.x() - p_new.x(), height + p.y() - p_new.y())

        self.updateSizeGripItem([i])

    def addGripItem(self):
        """adds grip items
        """
        if self.scene() and not self.lineGripItems:
            for i, (direction) in enumerate(
                    (
                            Qt.Vertical,
                            Qt.Horizontal,
                            Qt.Vertical,
                            Qt.Horizontal,
                    )
            ):
                item = SizeGripItem(self, i, direction)
                self.scene().addItem(item)
                self.sizeGripItems.append(item)

    def updateSizeGripItem(self, index_no_updates=None):
        """updates grip items
        """
        index_no_updates = index_no_updates or []
        for i, item in zip(range(len(self.sizeGripItems)), self.sizeGripItems):
            if i not in index_no_updates:
                item.update_position()

    def itemChange(self, change, value):
        """Overloads and extends QGraphicsSvgItem to also update gripitem
        """
        if change == QGraphicsItem.ItemPositionHasChanged:
            self.updateSizeGripItem()
            return
        if change == QGraphicsItem.ItemSceneHasChanged:
            self.addGripItem()
            self.updateSizeGripItem()
            return
        return super(NodeItem, self).itemChange(change, value)

if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = QMainWindow()
        window.show()
        scene = QGraphicsScene()
        scene.setSceneRect(0, 0, 200, 200)

        view = QGraphicsView()
        view.setScene(scene)
        window.setCentralWidget(view)
        scene.addItem(NodeItem())

        sys.exit(app.exec_())

test.svg

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="29.681765mm"
   height="50.584301mm"
   viewBox="0 0 29.681765 50.584301"
   version="1.1"
   id="svg1553"
   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
   sodipodi:docname="Column.svg">
  <defs
     id="defs1547" />
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.98994949"
     inkscape:cx="-53.758603"
     inkscape:cy="95.455126"
     inkscape:document-units="mm"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1304"
     inkscape:window-height="745"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1" />
  <metadata
     id="metadata1550">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(-144.63496,-116.2188)">
    <g
       id="use23287"
       transform="matrix(1.9494464,0,0,1.7251648,-371.93598,227.29603)">
      <g
         id="g1584"
         transform="matrix(0.68957937,0,0,-0.68957937,351.75302,3137.4373)">
        <desc
           id="desc1570">Column</desc>
        <title
           id="title1572">Column</title>
        <path
           d="m -125.4754,4606.3318 c 0.938,-3.094 5.438,-5.344 10.684,-5.344 5.25,0 9.746,2.25 10.687,5.344 v 31.129 c -0.941,3.094 -5.437,5.34 -10.687,5.34 -5.246,0 -9.746,-2.246 -10.684,-5.34 z"
           style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;vector-effect:non-scaling-stroke"
           id="path1574"
           inkscape:connector-curvature="0" />
        <g
           id="g1578"
           transform="matrix(1,0,0,-1,-164.4244,6574.5584)">
          <path
             d="m 38.949,1968.227 c 0.938,3.093 5.438,5.343 10.684,5.343 5.25,0 9.746,-2.25 10.687,-5.343 v -31.129 c -0.941,-3.094 -5.437,-5.34 -10.687,-5.34 -5.246,0 -9.746,2.246 -10.684,5.34 z m 0,0 H 60.32 M 38.949,1937.098 H 60.32"
             style="vector-effect:non-scaling-stroke;stroke-width:0.70875001;fill:none;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
             id="path1576"
             inkscape:connector-curvature="0" />
        </g>
      </g>
    </g>
  </g>
</svg>

в пи c i потоковое изображение элемента с помощью элемента захвата (показано вертикальной линией слева), затем между элементом захвата и границей изображения создается зазор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...