【问题标题】:Update position of custom QGraphicsItem on connected item change在连接项目更改时更新自定义 QGraphicsItem 的位置
【发布时间】:2016-10-14 08:17:40
【问题描述】:

我有两个子类 QGraphicsRectItems,它们应该与根据文本框的位置进行调整的线相连。

在 Qt 文档的 diagramscene example 中,QGraphicsPolygonItem 的子类 itemChanged 方法调用连接箭头的 updatePosition 方法,该方法调用 setLine 来更新箭头的位置。在我的情况下,我不能调用 setLine,因为我正在继承 QGraphicsItem 而不是 QGraphicsLineItem

我应该如何在下面的Arrow 类中实现updatePosition 方法来更新我的QGraphicsItem 的位置?以下是一个可运行的示例,显示了单击和移动文本框时当前发生的情况。

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_())

【问题讨论】:

  • 最简单的 omho 方法是使用 QGraphicsItemGroup 或父子关系。在那之后你不需要做任何花哨的事情来让事情一起移动,因为这两种方法可以解决所有这些问题。
  • 我可以看到您的建议适用于所有项目同时移动但其他项目不移动的情况。是这样吗?
  • 我不这么认为。所以基本上你想“拉伸”连接但只移动你选择的节点?如果是这样,请查看here。它在移动鼠标时显示绘图,这基本上是您想要做的 - 每当您移动其中一个节点时,您需要重新创建连接并更新它,直到移动的节点被单独留下,在这种情况下,您只需放置最后一个状态移动的连接将成为最后一个连接。
  • 对于TextBox 类,我现在实现了鼠标按下/释放事件来切换更新模式和调用arrow.update() 来触发绘制事件的mouseMoveEvent。我可以看到正在触发绘制事件,但由于某种原因,我仍然得到与 gif 中相同的行为。
  • 通常当你得到糟糕的绘图时,这是因为边界框不正确。如果您尝试在边界框外绘制,则会出现 GIF 中出现的那种故障行为。

标签: python c++ qt pyqt qgraphicsitem


【解决方案1】:

项目的位置实际上并不重要 - 它可以保持在 0,0 - 只要边界框正确(它将根据您的 Arrow::boundingBox 实现)。因此,我认为如果您只是触发边界框更改,并在 updatePosition 中重绘,一切都会按您的意愿进行。

当然,如果您关心箭头的位置是在线的头部或尾部,您可以在 updatePosition 中移动它,并相应地调整边界框/绘制坐标 - 但如果那样的话,这完全取决于您有没有道理。

【讨论】:

  • 如何触发边界框更改和重绘?我已经尝试使用self.prepareGeometryChange()self.update()updatePosition 中执行此操作,但仍然得到相同的行为。
  • 现在完美运行!除了我上面提到的我必须在TextBox init 中设置ItemSendsGeometryChanges 标志,并在boundingRectboundingRect 方法中将QSizeF(abs(bounds.x()), abs(bounds.y()) 更改为QSizeF(bounds.x(), bounds.y())
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-11
  • 1970-01-01
  • 2017-12-04
相关资源
最近更新 更多