使用 PySide6 中的 Qt,我想将
QGraphicsSimpleTextItem
置于其父项的 boundingRect
内。显然,我希望文本始终具有相同的缩放比例,而与我在视图上应用的转换无关。如果有必要,也可以保持相同的缩放比例,并且如果它跨越父级的矩形,则将其隐藏。
我用 fitInView(visible_rect, Qt.IgnoreAspectRatio)
设置视图转换。但我不知道如何正确地做到这一点。
我尝试在文本项上设置
ItemIgnoresTransformations
标志,但缩放和居中不起作用。
我尝试重写
paintEvent
方法并计算正确的位置和缩放比例(这才是正确的方法),但我也失败了。此时 paintEvent
看起来像这样:
def paint(self, painter, option, widget=...):
painter.setFont(self._font)
painter.setPen(QColor("purple"))
x_cen = self.parentItem().boundingRect().center().x()
y_cen = self.parentItem().boundingRect().center().y()
center = painter.worldTransform().map(x_cen, y_cen)
painter.setTransform(QTransform())
painter.drawText(center[0], center[1], self.text)
不变形居中没问题。有人有类似的问题或者只是知道如何在
QGraphicsSimpleTextItem
上应用正确的转换吗?
覆盖标准图形项的
paint()
通常应被视为最后一个资源,并且最好使用预定义的行为,因为它已经考虑了应用于整个视图/场景/对象树的所有相对变换。
ItemIgnoresTransformations
是正确的,但我们必须记住,这将忽略所有变换,这些变换也被考虑为项目相对于父级(包括场景)的位置。
如果您尝试根据文本项的边界矩形来定位文本项,则只要忽略转换,该方法就无效,因为平移将采用“绝对”坐标,而您需要的是相对于父项的位置,相反,确实使用变换(缩放)。
一个可能的解决方案是使用 QGraphicsItem 子类作为“代理”中间体,并将文本项添加为其子项。然后我们可以轻松地将文本项的位置翻译到“代理”的原点,然后我们需要的就是将其定位在父矩形的中心:
class CenterText(QGraphicsItem):
def __init__(self, text='', parent=None):
super().__init__(parent)
self.setFlag(self.ItemIgnoresTransformations)
self.textItem = QGraphicsSimpleTextItem(text, self)
self.textItem.setPos(-self.textItem.boundingRect().center())
def setText(self, text):
self.textItem.setText(text)
self.textItem.setPos(-self.textItem.boundingRect().center())
def boundingRect(self):
return self.childrenBoundingRect()
def paint(self, *args):
pass
class View(QGraphicsView):
def __init__(self):
scene = QGraphicsScene()
super().__init__(scene)
self.setRenderHint(QPainter.Antialiasing)
scene.setSceneRect(0, 0, 640, 480)
r = scene.addRect(200, 200, 80, 20)
r.setFlag(r.ItemIsMovable)
text = CenterText('Hello world!', r)
text.setPos(r.rect().center())
def resizeEvent(self, event):
super().resizeEvent(event)
self.fitInView(self.sceneRect())
那么,绘制文字能否完整显示的问题就有点微妙了。
最简单的解决方案是不阻止绘图,而是剪切它。 QGraphicsItem 提供
ItemClipsChildrenToShape
标志,确保项目的子项永远不会绘制在父项的边界矩形之外。r.setFlag(r.ItemClipsChildrenToShape)
,文本就会被包含在父矩形内。
或者,因为我们确信文本项不使用转换,所以我们可以覆盖
paint()
并检查 if 画家正在剪裁并且其剪裁矩形不包括文本项的边界矩形(实际上是形状)文本项目。
class HideableText(QGraphicsSimpleTextItem):
def paint(self, qp, opt, widget=None):
if qp.clipBoundingRect().contains(self.boundingRect()):
super().paint(qp, opt, widget)
class CenterText(QGraphicsItem):
def __init__(self, text='', parent=None):
super().__init__(parent)
self.setFlag(self.ItemIgnoresTransformations)
self.textItem = HideableText(text, self)
self.textItem.setPos(-self.textItem.boundingRect().center())
... as above