在连接的项目更改时更新自定义 QGraphicsItem 的位置
Update position of custom QGraphicsItem on connected item change
我有两个子classed QGraphicsRectItems,它们应该与一条根据文本框位置调整的线相连。
在 Qt 文档的 diagramscene example 中,subclassed 的 itemChanged
方法 QGraphicsPolygonItem
调用连接箭头的 updatePosition
方法调用 setLine
更新箭头的位置。在我的例子中,我不能调用 setLine
,因为我是 subclassing QGraphicsItem
而不是 QGraphicsLineItem
.
我应该如何实现下面Arrow
class中的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_())
项目的位置实际上并不重要 - 它可以保持在 0,0 - 只要边界框是正确的(这将根据你的 Arrow::boundingBox 实施)。因此,我认为如果您只是触发边界框更改,并在 updatePosition 中重绘,一切都会如您所愿。
当然,如果您关心箭头的位置是在线的头部还是尾部,您可以在 updatePosition 中移动它,并相应地调整边界框/绘制坐标 - 但这完全取决于您是否有意义。
我有两个子classed QGraphicsRectItems,它们应该与一条根据文本框位置调整的线相连。
在 Qt 文档的 diagramscene example 中,subclassed 的 itemChanged
方法 QGraphicsPolygonItem
调用连接箭头的 updatePosition
方法调用 setLine
更新箭头的位置。在我的例子中,我不能调用 setLine
,因为我是 subclassing QGraphicsItem
而不是 QGraphicsLineItem
.
我应该如何实现下面Arrow
class中的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_())
项目的位置实际上并不重要 - 它可以保持在 0,0 - 只要边界框是正确的(这将根据你的 Arrow::boundingBox 实施)。因此,我认为如果您只是触发边界框更改,并在 updatePosition 中重绘,一切都会如您所愿。
当然,如果您关心箭头的位置是在线的头部还是尾部,您可以在 updatePosition 中移动它,并相应地调整边界框/绘制坐标 - 但这完全取决于您是否有意义。