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

PyQt5中QFontMetrics获取文本尺寸与drawText绘制结果不符问题

问题描述

需要获取文本尺寸以缩放适配指定区域,但QFontMetrics.width()返回结果存在偏差。绘制文本后,用QFontMetrics获取的尺寸绘制的矩形仅为文本的约一半,且不同文本对应的比例系数不固定,无法通过固定倍数修正。

代码示例:

from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtGui import QPainter, QTextDocument, QFont, QFontMetrics
from PyQt5.QtCore import QRect, Qt, QRectF
import sys

font = QFont("times",10)
fm = QFontMetrics(font)


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon("icon.png"))
        self.show()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setFont(font)
        sText = 'Hello World!'
        painter.drawText(0,100, sText)
        pixelsWide = fm.width(sText)
        pixelsHigh = fm.height()
        painter.drawRect(0, 100, pixelsWide, pixelsHigh)


App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

效果截图:
文本与矩形偏差效果

问题原因及解决方法

核心原因

  1. QFontMetrics.width()的局限性:该方法返回的是文本的前进宽度(advance width),即文本绘制后光标移动的距离,并非文本实际占用的完整水平空间;且全局创建的QFontMetrics可能和painter的字体渲染上下文不匹配(比如高DPI环境下的缩放差异)。
  2. 坐标基准不一致:drawText(0,100, sText)的第二个参数是文本的**基线(baseline)**位置,而drawRect的y参数是矩形的顶部,直接用fm.height()会导致矩形垂直位置和高度都偏离文本实际区域。

修正方案

  • 从当前painter获取QFontMetrics,确保字体上下文与渲染环境一致。
  • 使用boundingRect()方法获取文本的准确包围矩形,该方法会返回文本实际占用的完整区域(包括左右边距、上下的 ascent/descent)。

修正后的代码:

from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtGui import QPainter, QFont, QFontMetrics
from PyQt5.QtCore import QRect, Qt
import sys

font = QFont("times",10)


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon("icon.png"))
        self.show()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setFont(font)
        sText = 'Hello World!'
        
        # 从painter获取当前字体的metrics,保证上下文一致
        fm = painter.fontMetrics()
        # 获取文本的准确包围矩形,指定绘制基线位置为(0,100),自动计算尺寸
        text_rect = fm.boundingRect(0, 100, 0, 0, Qt.TextSingleLine, sText)
        
        painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignTop, sText)
        painter.drawRect(text_rect)


App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

说明

  • fm.boundingRect(x, y, width, height, flags, text)中,将width和height设为0,让Qt自动计算文本所需尺寸;Qt.TextSingleLine确保文本不换行。
  • 绘制文本时使用text_rect作为目标区域,保证文本和矩形完全对齐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:40:40