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

如何基于任意文本长度获取QGraphicsItem的boundingRect边界框

解决方案

Qt 提供了QFontMetricsF类可以直接计算文本的实际像素占用尺寸,完全不需要手动根据字符数估算,能自动适配不同字体、字号、字符宽度差异(比如i和w的宽度差异)。

你只需要修改MapMarker类,将固定边界框改为动态计算图标+文本的合并边界即可,推荐同时缓存计算结果提升性能:

具体修改步骤

  1. 新增边界缓存变量,避免每次调用boundingRect都重复计算
  2. 分别计算图标形状的边界、文本的实际边界,合并后作为整体边界框
  3. 如果后续需要动态修改标签内容,修改后清空缓存并通知Qt更新几何信息即可

修改后的完整MapMarker类代码

class MapMarker(QGraphicsItem):
    def __init__(self, marker, label):
        super().__init__()
        self.marker = marker
        self.label = label
        # 新增:边界缓存
        self._cached_bound = None
        # 可选:自定义标签字体,用默认字体也可以
        self.label_font = QFont("Microsoft Yahei", 9)

        # Build QPolygon dictionary from SHAPES coordinates
        self.shapes = {}
        for k, v in SHAPES.items():
            self.shapes[k] = QPolygon([QPoint(*point)for point in SHAPES[k]])

        # Set marker color
        self.color = QColor(MARKERS[self.marker]['color'])

    def _calc_bound(self):
        """计算图标+文本的合并边界框"""
        # 1. 计算图标部分的边界
        shape_name = MARKERS[self.marker]['shape']
        if shape_name == 'circle':
            shape_rect = QRectF(-4, -4, 8, 8)
        else:
            shape_rect = QRectF(self.shapes[shape_name].boundingRect())
        
        # 2. 计算文本实际边界
        fm = QFontMetricsF(self.label_font)
        text_rect = fm.boundingRect(self.label)
        # 偏移到你绘制文本的坐标(你绘制时用的是(10, -2)作为文本基准点)
        text_rect.translate(10, -2)

        # 3. 合并两个边界,加1px边距避免边缘被裁剪
        self._cached_bound = shape_rect.united(text_rect).adjusted(-1, -1, 1, 1)

    def paint(self, painter, option, widget):
        brush = QBrush(Qt.SolidPattern)
        brush.setColor(self.color)
        painter.setPen(QPen(self.color))
        painter.setBrush(brush)

        # Draw marker shape
        shape_name = MARKERS[self.marker]['shape']
        if shape_name == 'circle':
            painter.drawEllipse(-4, -4, 8, 8)
        else:
            painter.drawPolygon(self.shapes[shape_name])

        # Draw marker label:设置自定义字体(如果有的话)
        painter.setFont(self.label_font)
        painter.drawText(10, -2, self.label)

    def boundingRect(self):
        # 缓存不存在时才重新计算
        if not self._cached_bound:
            self._calc_bound()
        return self._cached_bound

    # 可选:如果需要动态修改标签,新增这个方法
    def update_label(self, new_label):
        self.label = new_label
        # 清空缓存,通知Qt边界已经变化
        self._cached_bound = None
        self.prepareGeometryChange()
        self.update()

补充说明

如果需要更精准的碰撞检测(比如点击标签外的空白区域不算选中),可以额外重载shape()方法,返回图标+文本的实际形状路径,交互体验会更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 17:30:05