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())
效果截图:
问题原因及解决方法
核心原因
QFontMetrics.width()的局限性:该方法返回的是文本的前进宽度(advance width),即文本绘制后光标移动的距离,并非文本实际占用的完整水平空间;且全局创建的QFontMetrics可能和painter的字体渲染上下文不匹配(比如高DPI环境下的缩放差异)。- 坐标基准不一致:
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
相关产品推荐
相关产品推荐

