<p>所有QGraphicsItem子类都有一个<code>paint</code>方法,所有绘制某些内容的项都覆盖了该方法,以便它们实际上可以绘制</em>自己</p>
<p>该机制与标准QWidgets相同,对于标准QWidgets,有一个<code>paintEvent</code>(区别在于QGraphicsItem的<code>paint</code>接收一个已经实例化的QPaint),因此,如果您想在类已经提供的基础上进一步绘制<em>其他</em>,则必须调用基本实现</p>
<P>认为绘画总是自下而上,所以需要画出的东西<EM>后面的EEM >底漆必须在<EEM >之前调用eEM>调用^ {CD4>},并且缺省绘画的前面<EEM >中的所有东西都要放在<EM>后<EEM>。p>
<p>根据具体情况,重写可能需要调用默认的基本实现,这对于<code>boundingRect</code>来说也很重要。QGraphicsTextItem在其内容更改时自动调整自身大小,因此不应总是返回固定的QRect。如果需要最小大小,解决方案是将最小矩形<em>与默认<code>boundingRect()</code>函数提供的</em>合并</p>
<p>然后,在QGraphicsTextItem上进行编辑时,项目会被聚焦到<em>上</em>,但由于您也希望能够移动项目,所以这两个操作都是基于鼠标单击的,因此操作会变得更加复杂。如果您希望能够通过单击编辑文本,解决方案是当鼠标按钮被释放<em>并且</em>没有移动一定数量的像素时(即<a href="https://doc.qt.io/qt-5/qapplication.html#startDragDistance-prop" rel="nofollow noreferrer">^{<cd7>}</a>属性),使项目仅可编辑<em>,否则项目将随鼠标移动。这显然使<code>ItemIsMovable</code>标志无用,因为我们将在内部处理该运动</p>
<p>最后,由于提供了最小大小,我们还需要重写<a href="https://doc.qt.io/qt-5/qgraphicsitem.html#shape" rel="nofollow noreferrer">^{<cd9>}</a>方法,以确保正确映射碰撞和单击,并返回包含整个边界rect的QPainterPath(对于正常的QGraphicsSitem,这应该是默认行为,但QGraphicsRecItem不会发生)</p>
<p>下面是上述内容的完整实现:</p>
<pre class="lang-py prettyprint-override"><code>class NodeTag(QGraphicsTextItem):
def __init__(self, text):
QGraphicsTextItem.__init__(self, text)
self.startPos = None
self.isMoving = False
# the following is useless, not only because we are leaving the text
# painting to the base implementation, but also because the text is
# already accessible using toPlainText() or toHtml()
#self.text = text
# this is unnecessary too as all new items always have a (0, 0) position
#self.setPos(0, 0)
def boundingRect(self):
return super().boundingRect() | QRectF(0, 0, 80, 25)
def paint(self, painter, option, widget):
# draw the border *before* (as in "behind") the text
painter.setPen(QPen(Qt.blue, 2, Qt.SolidLine))
painter.drawRect(self.boundingRect())
super().paint(painter, option, widget)
def shape(self):
shape = QPainterPath()
shape.addRect(self.boundingRect())
return shape
def focusOutEvent(self, event):
# this is required in order to allow movement using the mouse
self.setTextInteractionFlags(Qt.NoTextInteraction)
def mousePressEvent(self, event):
if (event.button() == Qt.LeftButton and
self.textInteractionFlags() != Qt.TextEditorInteraction):
self.startPos = event.pos()
else:
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.startPos:
delta = event.pos() - self.startPos
if (self.isMoving or
delta.manhattanLength() >= QApplication.startDragDistance()):
self.setPos(self.pos() + delta)
self.isMoving = True
return
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if (not self.isMoving and
self.textInteractionFlags() != Qt.TextEditorInteraction):
self.setTextInteractionFlags(Qt.TextEditorInteraction)
self.setFocus()
# the following lines are used to correctly place the text
# cursor at the mouse cursor position
cursorPos = self.document().documentLayout().hitTest(
event.pos(), Qt.FuzzyHit)
textCursor = self.textCursor()
textCursor.setPosition(cursorPos)
self.setTextCursor(textCursor)
super().mouseReleaseEvent(event)
self.startPos = None
self.isMoving = False
</code></pre>
<p>作为旁注,请记住QGraphicsTextItem支持富文本格式,因此即使您希望对文本绘制过程进行更多控制,也不应使用^{<cd10>,因为您只需绘制<em>纯文本</em>。事实上,QGraphicsTextItem使用底层<a href="https://doc.qt.io/qt-5/qgraphicstextitem.html#document" rel="nofollow noreferrer">text document</a>的<a href="https://doc.qt.io/qt-5/qtextdocument.html#drawContents" rel="nofollow noreferrer">^{<cd11>}</a>函数绘制其内容</p>