2017-10-24 13 views
2

私は偉大な実装をthis answerから拡張しようとしているので、パスはグラフィックシーン内のユーザーのクリックから作成され、ダブルクリックを使用してパスを閉じます。QGraphicSceneで移動可能なノードで閉じたパスを作成する

これはうまくいきますが、私がまだ解決できなかった唯一の問題は、パス内の最初のノードの変更です。明らかに私はそれがitemChangedメソッドを介してそれに接続された最後のサブパスを更新することを望むが、それが起こることができませんでした。

これにアプローチする方法についてのご意見はありますか?

私は、次のバリエーションを試してみましたが、それは最後のサブパスに影響を及ぼさなかった。

def itemChange(self, change, value): 
    if change == QGraphicsItem.ItemPositionChange: 
     self.path.updateElement(self.index, value.toPoint()) 
     if self.index == 0: 
      last_element_idx = self.path.path.elementCount() 
      self.path.updateElement(last_element_idx, value.toPoint()) 
    return QGraphicsEllipseItem.itemChange(self, change, value) 

私の実験のための完全なコード:

from PyQt5 import QtCore, QtGui 
from PyQt5.QtCore import QPointF, Qt 
from PyQt5.QtGui import QPen, QPainterPath, QPainter, QPolygonF 
from PyQt5.QtWidgets import QGraphicsEllipseItem, QGraphicsItem, QGraphicsPathItem, QApplication, QGraphicsScene, \ 
    QGraphicsView, QFrame, QMainWindow 

rad = 3 

class Node(QGraphicsEllipseItem): 
    def __init__(self, path, index): 
     super(Node, self).__init__(-rad, -rad, 2*rad, 2*rad) 
     self.rad = rad 
     self.path = path 
     self.index = index 
     self.setZValue(1) 
     self.setFlag(QGraphicsItem.ItemIsMovable) 
     self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) 
     self.setBrush(Qt.green) 

    def itemChange(self, change, value): 
     if change == QGraphicsItem.ItemPositionChange: 
      self.path.updateElement(self.index, value.toPoint()) 
      if self.index == 0: 
       last_element_idx = self.path.path.elementCount() 
       self.path.updateElement(last_element_idx, value.toPoint()) 
     return QGraphicsEllipseItem.itemChange(self, change, value) 

class Path(QGraphicsPathItem): 
    def __init__(self, pos, scene): 
     self.path = QPainterPath() 
     self.path.moveTo(*pos) 
     super(Path, self).__init__(self.path) 
     self.scene = scene 
     self.pos = pos 
     self.setPen(QPen(Qt.red, 1.75)) 
     self.scene.addItem(self) 

    def addElement(self, pos): 
     self.path.lineTo(QPointF(*pos)) 
     self.setPath(self.path) 
     self.scene.update() 

    def closePath(self): 
     self.path.closeSubpath() 
     n = self.path.elementCount() 
     for i in range(n-1): 
      node = Node(self, i) 
      elem = self.path.elementAt(i) 
      node.setPos(elem.x, elem.y) 
      self.scene.addItem(node) 
     self.setPath(self.path) 
     self.scene.update() 

    def updateElement(self, index, pos): 
     self.path.setElementPositionAt(index, pos.x(), pos.y()) 
     self.setPath(self.path) 
     self.scene.update() 

class GraphicViewer(QGraphicsView): 
    def __init__(self, parent, img=None, masks=None): 
     super(GraphicViewer, self).__init__(parent) 
     self.img = img 
     self._scene = QGraphicsScene(self) 
     self._scene.setSceneRect(0, 0, 1920, 900) 
     self.setScene(self._scene) 
     self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) 
     self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) 
     self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 
     self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 
     self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(0, 0, 0))) 
     self.setFrameShape(QFrame.NoFrame) 
     self.setRenderHint(QPainter.Antialiasing) 
     self.resize(1920, 900) 
     self.editable_path = None 

    def mousePressEvent(self, event: QtGui.QMouseEvent): 
     modifiers = QApplication.keyboardModifiers() 
     if modifiers == QtCore.Qt.AltModifier: 
      self.pos = (event.x(), event.y()) 
      if self.editable_path is None: 
       self.editable_path = Path(self.pos, self._scene) 
      else: 
       self.editable_path.addElement(self.pos) 
     else: 
      super(GraphicViewer, self).mousePressEvent(event) 

    def mouseDoubleClickEvent(self, event: QtGui.QMouseEvent): 
     if self.editable_path is not None: 
      self.editable_path.closePath() 
      self.editable_path = None 

if __name__ == "__main__": 

    app = QApplication([]) 
    MainWindow = QMainWindow() 
    view = GraphicViewer(MainWindow) 
    MainWindow.resize(1920, 900) 
    MainWindow.show() 
    app.exec_() 

答えて

1

をあなたはほとんどそれを持っていましたが、あなたのitemChange方法がありoff-by-oneエラーです。

私はこのように見てあなたの例を再記述します。

class Node(QGraphicsEllipseItem): 
    ... 
    def itemChange(self, change, value): 
     if change == QGraphicsItem.ItemPositionChange: 
      self.path.updateElement(self.index, value.toPoint()) 
     return QGraphicsEllipseItem.itemChange(self, change, value) 

class Path(QGraphicsPathItem): 
    ...  
    def updateElement(self, index, pos): 
     self.path.setElementPositionAt(index, pos.x(), pos.y()) 
     if index == 0: 
      self.path.setElementPositionAt(
       self.path.elementCount() - 1, pos.x(), pos.y()) 
     self.setPath(self.path) 
     self.scene.update() 
関連する問題