2016-06-13 1 views
2

텍스트 상자의 위치에 따라 조정되는 줄과 연결된 것으로 가정되는 두 개의 서브 클래 싱 된 QGraphicsRectItem이 있습니다. Qt는의 diagramscene example에서연결된 항목 변경시 사용자 지정 QGraphicsItem의 위치 업데이트

QGraphicsPolygonItem는 서브 클래스의 메소드 itemChanged 화살표의 위치를 ​​업데이트 setLine 호출 연결된 화살표의 updatePosition 메소드를 호출 도쿠. 내 경우에는 setLineQGraphicsLineItem 대신에 QGraphicsItem 서브 클래 싱으로 호출 할 수 없습니다.

아래의 Arrow 클래스에 updatePosition 메서드를 구현하여 내 QGraphicsItem의 위치를 ​​업데이트하려면 어떻게해야합니까? 다음은 텍스트 상자를 클릭하고 이동할 때 현재 일어나는 일을 보여주는 실행 가능한 예제입니다.

enter image description here

import sys 
from PyQt4.QtGui import * 
from PyQt4.QtCore import * 


class Arrow(QGraphicsItem): 

    def __init__(self, startItem, endItem, parent=None, scene=None): 
     super().__init__(parent, scene) 

     self.startItem = startItem 
     self.endItem = endItem 

    def boundingRect(self): 
     p1 = self.startItem.pos() + self.startItem.rect().center() 
     p3 = self.endItem.pos() + self.endItem.rect().center() 
     bounds = p3 - p1 
     size = QSizeF(abs(bounds.x()), abs(bounds.y())) 
     return QRectF(p1, size) 

    def paint(self, painter, option, widget=None): 

     p1 = self.startItem.pos() + self.startItem.rect().center() 
     p3 = self.endItem.pos() + self.endItem.rect().center() 

     pen = QPen() 
     pen.setWidth(1) 
     painter.setRenderHint(QPainter.Antialiasing) 

     if self.isSelected(): 
      pen.setStyle(Qt.DashLine) 
     else: 
      pen.setStyle(Qt.SolidLine) 

     pen.setColor(Qt.black) 
     painter.setPen(pen) 
     painter.drawLine(QLineF(p1, p3)) 
     painter.setBrush(Qt.NoBrush) 

    def updatePosition(self): 
     #Not sure what to do here... 


class TextBox(QGraphicsRectItem): 

    def __init__(self, text, position, rect=QRectF(0, 0, 200, 100), 
       parent=None, scene=None): 
     super().__init__(rect, parent, scene) 

     self.setFlags(QGraphicsItem.ItemIsFocusable | 
         QGraphicsItem.ItemIsMovable | 
         QGraphicsItem.ItemIsSelectable) 

     self.text = QGraphicsTextItem(text, self) 

     self.setPos(position) 

     self.arrows = [] 

    def paint(self, painter, option, widget=None): 
     painter.setPen(Qt.black) 
     painter.setRenderHint(QPainter.Antialiasing) 
     painter.setBrush(Qt.white) 
     painter.drawRect(self.rect()) 

    def addArrow(self, arrow): 
     self.arrows.append(arrow) 

    def itemChange(self, change, value): 
     if change == QGraphicsItem.ItemPositionChange: 
      for arrow in self.arrows: 
       arrow.updatePosition() 

     return value 


if __name__ == "__main__": 

    app = QApplication(sys.argv) 

    view = QGraphicsView() 
    scene = QGraphicsScene() 
    scene.setSceneRect(0, 0, 500, 1000) 
    view.setScene(scene) 

    textbox1 = TextBox("item 1", QPointF(50, 50), scene=scene) 
    textbox1.setZValue(1) 
    textbox2 = TextBox("item 2", QPointF(100, 500), scene=scene) 
    textbox2.setZValue(1) 

    arrow = Arrow(textbox1, textbox2, scene=scene) 
    arrow.setZValue(0) 

    textbox1.addArrow(arrow) 
    textbox2.addArrow(arrow) 

    view.show() 

    sys.exit(app.exec_()) 
+0

가장 쉬운 방법은'QGraphicsItemGroup' 또는 부모 - 자식 관계를 사용하는 것입니다. 이 두 가지 방법으로 모든 것을 처리하기 때문에 함께 움직이게하기 위해 그 후에 아무 것도 할 필요가 없습니다. – rbaleksandar

+0

나는 모든 항목이 동시에 움직이지만 다른 하나는 움직이지 않는 경우에 대한 제안을 볼 수 있습니다. 그럴까요? – pbreach

+1

나는 그렇게 생각하지 않는다. 기본적으로 연결을 "확장"하지만 선택한 노드 만 이동하려고합니까? 그렇다면 여기를보십시오 (http://www.walletfox.com/course/qgraphicsitemruntimedrawing.php). 기본적으로 원하는대로 마우스를 움직이는 동안 드로잉을 보여줍니다. 노드 중 하나를 움직일 때마다 연결을 다시 만들고 이동 된 노드가 홀로 남을 때까지 업데이트해야합니다.이 경우 노드의 마지막 상태 이동 된 연결이 마지막 연결이됩니다. – rbaleksandar

답변

3

이 항목의 위치는 실제로 중요하지 않습니다 - 그것은 0,0에 남아있을 수 있습니다 - 제공 그것은 당신의 화살표에 따라 될 경계 상자는 (정확 :: BoundingBox의 구현). 따라서 바운딩 박스 변경을 트리거하고 updatePosition에서 다시 그리기 만하면 원하는대로 모든 것이 작동한다고 생각합니다.

화살표의 위치가 선의 꼬리 또는 꼬리가 걱정되는 경우 updatePosition에서 화살표의 위치를 ​​이동하고 이에 따라 경계 상자/페인트 좌표를 조정할 수 있습니다. 그것은 의미가 있습니다.

+0

바운딩 박스를 변경하고 다시 그리려면 어떻게해야합니까? 나는'self.prepareGeometryChange()'와'self.update()'를 사용하여'updatePosition'에서 이것을 시도했지만 여전히 같은 행동을하고있다. – pbreach

+1

완벽하게 작동합니다! 앞서 언급 한 것 외에도'TextBox' init에'ItemSendGeometryChanges' 플래그를 설정하고'QSizeF (abs (bounds.x()), abs (bounds.y())'를'QSizeF (bounds 'Arrow'의'boundingRect' 메쏘드에서 .x(), bounds.y())' – pbreach

관련 문제