将 QGraphicsSimpleTextItem 置于变换视图上的父项中

问题描述 投票:0回答:1

使用 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
上应用正确的转换吗?

qt pyqt pyside pyside6
1个回答
0
投票

覆盖标准图形项的

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
© www.soinside.com 2019 - 2024. All rights reserved.