2017-10-24 4 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) 

내 실험의 전체 코드 :

당신은 거의 그것을했다,하지만 itemChange 방법이
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

오프 - 바이 - 원 오류.

I는 다음과 같이 귀하의 예를 다시 작성합니다

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() 
관련 문제