You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySide6中如何让QGraphicsSimpleTextItem在父项居中且不受视图变换影响?

解决方案

方法1:使用ItemIgnoresTransformations并动态更新位置

设置ItemIgnoresTransformations后,文本项的坐标系统会切换到视图坐标系(而非父项的局部坐标系),直接用父项局部坐标计算中心会失效,需要通过坐标转换同步位置,同时可添加裁剪控制文本显示范围。

代码实现

from PySide6.QtWidgets import QGraphicsSimpleTextItem, QGraphicsItem
from PySide6.QtCore import Qt, QPointF, QRectF
from PySide6.QtGui import QPainter, QFont, QColor

class FixedCenterTextItem(QGraphicsSimpleTextItem):
    def __init__(self, text, parent=None):
        super().__init__(text, parent)
        self.setFlag(QGraphicsItem.ItemIgnoresTransformations)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self._font = QFont("Arial", 12)
        self.setFont(self._font)
        self.update_text_position()

    def update_text_position(self):
        if not self.parentItem():
            return
        # 获取父项局部坐标系中心,转换为视图坐标系坐标
        parent_center = self.parentItem().boundingRect().center()
        view_pos = self.parentItem().mapToScene(parent_center)
        self_pos = self.mapFromScene(view_pos)
        # 偏移文本自身尺寸的一半,实现真正居中
        text_rect = self.boundingRect()
        self.setPos(self_pos - QPointF(text_rect.width()/2, text_rect.height()/2))

    def itemChange(self, change, value):
        # 监听父项几何/变换变化,实时更新位置
        if change in (QGraphicsItem.ItemParentChange, QGraphicsItem.ItemParentHasChanged):
            self.update_text_position()
        elif change == QGraphicsItem.ItemSceneHasChanged:
            self.update_text_position()
        return super().itemChange(change, value)

    def paint(self, painter, option, widget=None):
        # 添加裁剪,隐藏超出父项范围的文本
        if self.parentItem():
            parent_rect = self.parentItem().boundingRect()
            clip_rect = self.mapFromParent(parent_rect).boundingRect()
            painter.setClipRect(clip_rect)
        painter.setPen(QColor("purple"))
        painter.setFont(self._font)
        super().paint(painter, option, widget)

方法2:重写paint方法,手动控制变换和位置

如果不想依赖ItemIgnoresTransformations,可在paint阶段暂时重置 painter 变换,同时通过坐标转换计算正确的绘制位置,添加裁剪逻辑。

代码实现

from PySide6.QtWidgets import QGraphicsSimpleTextItem, QGraphicsItem
from PySide6.QtCore import Qt, QPointF, QRectF
from PySide6.QtGui import QPainter, QFont, QColor, QTransform

class FixedCenterTextItem(QGraphicsSimpleTextItem):
    def __init__(self, text, parent=None):
        super().__init__(text, parent)
        self._font = QFont("Arial", 12)
        self.setFont(self._font)

    def paint(self, painter, option, widget=None):
        if not self.parentItem():
            super().paint(painter, option, widget)
            return

        # 保存原始变换,后续恢复
        original_transform = painter.worldTransform()
        # 将父项局部中心转换为视图坐标系位置
        parent_center = self.parentItem().boundingRect().center()
        scene_center = self.parentItem().mapToScene(parent_center)
        view_center = widget.mapFromScene(scene_center) if widget else scene_center

        # 重置painter变换,让文本不受视图缩放影响
        painter.setTransform(QTransform())

        # 计算文本居中绘制的偏移位置
        text_rect = self.boundingRect()
        draw_pos = QPointF(view_center.x() - text_rect.width()/2, 
                          view_center.y() - text_rect.height()/2)

        # 添加裁剪,隐藏超出父项范围的文本
        parent_scene_rect = self.parentItem().mapToScene(self.parentItem().boundingRect()).boundingRect()
        parent_view_rect = widget.mapFromScene(parent_scene_rect) if widget else parent_scene_rect
        painter.setClipRect(parent_view_rect)

        # 绘制文本
        painter.setPen(QColor("purple"))
        painter.setFont(self._font)
        painter.drawText(draw_pos, self.text())

        # 恢复原始变换
        painter.setTransform(original_transform)

关键注意事项

  • ItemIgnoresTransformations会让项脱离父项变换系统,必须通过mapToScene/mapFromScene完成坐标转换
  • 文本居中需考虑自身boundingRect,偏移一半尺寸才能实现真正的中心对齐
  • 裁剪功能需要将父项边界转换到对应坐标系(视图/局部),才能正确隐藏超出部分
  • 使用fitInView时,视图变换会影响场景坐标,必须依赖坐标转换同步位置

内容的提问来源于stack exchange,提问作者hollarob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:20:37