0

我正在子类QGraphicsItem化以创建一个地图标记,该标记绘制一个图标(基于多边形点的常量字典)和一个文本标签。

下面的boundingRect方法定义了一个固定的边界框矩形。但由于文本标签可以是任意长度,我需要每个标记实例的边界框不同(例如,用于选择和聚焦)。

如何根据字符在屏幕上占据的实际像素宽度获取每个标记实例的边界矩形?我是否需要根据字体大小和字符数手动估算?或者 Qt 可以自动计算吗?

import sys

from PySide6 import QtCore, QtWidgets
from PySide6.QtWidgets import (
    QApplication, QWidget, QHBoxLayout, QVBoxLayout,
    QGraphicsScene, QGraphicsView, QGraphicsItem
    )
from PySide6.QtGui import QColor, QFont, QPen, QBrush, QPolygon
from PySide6.QtCore import QPointF, Qt, QRectF, QPoint

MARKERS = {
    'peak': {'color': 'limegreen', 'shape': 'star'},
    'tag':  {'color': 'bisque', 'shape': 'x'},
    'pole': {'color': 'coral', 'shape': 'circle'}
    }

SHAPES = {
    'star': [(-1, -1), (0, -5), (1, -1), (5, 4), (0, 1), (-5, 4), (-1, -1)],
    'x': [(0, -2), (3, -5), (5, -3), (2, 0), (5, 3),
          (3, 5), (0, 2), (-3, 5), (-5, 3), (-2, 0), (-5, -3), (-3, -5)]
    }


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('Map')

        self.scene = MapScene()
        self.view = QGraphicsView(self.scene)

        # Main layout
        layout = QHBoxLayout()
        layout.addWidget(self.view)
        self.setLayout(layout)


class MapMarker(QGraphicsItem):
    def __init__(self, marker, label):
        super().__init__()
        self.marker = marker
        self.label = label

        # 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 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.drawText(10, -2, self.label)

    def boundingRect(self):
        return QRectF(-10, -15, 200, 30)


class MapScene(QGraphicsScene):

    def __init__(self):
        super().__init__()
        markers = [
            (10, 10, 'peak', 'Some peak'),
            (20, 30, 'tag', 'Some tag with a longer name'),
        ]

        # Draw markers
        for x, y, m, b in markers:
            marker = MapMarker(m, b)
            marker.setPos(x, y)
            self.addItem(marker)


if __name__ == '__main__':
    app = QApplication([])
    widget = MainWindow()
    widget.show()

    sys.exit(app.exec())

4

1 回答 1

1

您可以使用 QFontMetrics 或 QFontMetricsF(从 QtGui 导入)来获取boundingRect文本的 ,并与boundingRect图标的 结合。

def boundingRect(self):
    shape_name = MARKERS[self.marker]['shape']
    if shape_name == 'circle':
        icon_rect = QRectF(-4, -4, 8, 8)
    else:
        icon_rect = QRectF(self.shapes[shape_name].boundingRect())
        
    text_rect = QFontMetricsF(QFont()).boundingRect(self.label).translated(10, -2)
    
    return icon_rect | text_rect

我在末尾添加了这些行paint以验证照片中矩形的区域:

painter.setPen(QPen(Qt.black, 1, Qt.DashLine))
painter.setBrush(Qt.NoBrush)
painter.drawRect(self.boundingRect())

在此处输入图像描述

于 2021-07-19T01:20:35.600 回答