我试图得到QLabel的字体大小,文本填充整个QLabel的矩形,我尝试使用QFontMetrics来获取,但是QFontMetrics不能通过给定的矩形获得字体大小?
例子:
当调整窗口大小时,GUI可能会卡住。
class Label(QLabel):
def __init__(self):
super().__init__()
self.resize(400, 300)
font = self.calculate_font()
self.setFont(font)
self.setText('PASS')
def calculate_font(self):
for i in range(400):
fm = QFontMetrics( QFont('Helvetica', i) )
fmSize = fm.boundingRect(self.geometry(), Qt.AlignCenter, 'PASS').size()
print(fm.boundingRect(self.geometry(), Qt.AlignCenter, 'PASS'), self.size())
#need font height equal label height
if fmSize.height() > self.size().height():
return QFont('Helvetica', i)
def resizeEvent(self, event):
font = self.calculate_font()
self.setFont(font)
app = QApplication([])
demo = Label()
demo.show()
app.exec()发布于 2019-11-19 06:12:51
不要这样做
有几十个原因,你想要达到的是简单的错误。
最重要的是处理文本绘图,其大小是而不是,这是一项轻松的任务;此外,Qt使用标签内容来告诉窗口布局它可以拥有的大小、希望拥有的大小以及最重要的是它应该拥有的最小大小;所有这些对于GUI来说都是非常重要的,因为为了正确调整界面的所有其他元素,会考虑到这些内容。
最后,所有这些因素都基于标签的文本及其格式,这可能取决于文本内容和文本可能是“富文本”的事实(包括多字体大小和权重)。
如果您真的很清楚上面解释的概念,下面是4种可能的实现。它们都部分支持丰富的文本(字体权重、文本颜色等,但不支持真正的文本对齐)。

调整字体标签
虽然子类化QLabel似乎是最简单的方法,但实际上并非如此,因为它是一个比看起来复杂得多的小部件(正如我前面写的,处理文本小部件并不是一项容易的任务)
这种方法最重要的缺点是它非常慢,因为它必须仔细计算每次调整大小时的字体大小。虽然可以通过更好的实现来实现一些改进,但我还是不建议使用这种方法。
class ResizeFontLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.paintFont = self.font()
def updateFont(self):
doc = QTextDocument()
if self.textFormat() == Qt.RichText or self.textFormat() == Qt.AutoText and Qt.mightBeRichText(self.text()):
doc.setHtml(self.text())
else:
doc.setPlainText(self.text())
frame = doc.rootFrame().frameFormat()
frame.setMargin(0)
doc.rootFrame().setFrameFormat(frame)
doc.setDefaultFont(self.paintFont)
width = self.width()
height = self.height()
if doc.size().width() > width or doc.size().height() > height:
while doc.size().width() > width or doc.size().height() > height:
self.paintFont.setPointSizeF(self.paintFont.pointSizeF() - .1)
doc.setDefaultFont(self.paintFont)
elif doc.size().width() < width and doc.size().height() < height:
while doc.size().width() < width and doc.size().height() < height:
self.paintFont.setPointSizeF(self.paintFont.pointSizeF() + .1)
doc.setDefaultFont(self.paintFont)
def resizeEvent(self, event):
self.updateFont()
def paintEvent(self, event):
doc = QTextDocument()
if self.textFormat() == Qt.RichText or self.textFormat() == Qt.AutoText and Qt.mightBeRichText(self.text()):
doc.setHtml(self.text())
else:
doc.setPlainText(self.text())
frame = doc.rootFrame().frameFormat()
frame.setMargin(0)
doc.rootFrame().setFrameFormat(frame)
doc.setDefaultFont(self.paintFont)
qp = QPainter(self)
doc.drawContents(qp, QRectF(self.rect()))QLabels内部使用QTextDocument进行画图和调整大小。setMargin之所以出现这种情况,是因为QTextDocument在默认情况下有一定的裕度,而且在标签中没有使用。
备注:
updateFont()方法中的不同的updateFont()。他们的逻辑是非常重要的基于绘画的字体标签
该方法是对上述方法的简化。它不计算字体大小,但只绘制缩放到大小的内容。
class PaintLabel(QLabel):
def paintEvent(self, event):
doc = QTextDocument()
if self.textFormat() == Qt.RichText or self.textFormat() == Qt.AutoText and Qt.mightBeRichText(self.text()):
doc.setHtml(self.text())
else:
doc.setPlainText(self.text())
frame = doc.rootFrame().frameFormat()
frame.setMargin(0)
doc.rootFrame().setFrameFormat(frame)
scale = min(self.width() / doc.size().width(), self.height() / doc.size().height())
qp = QPainter(self)
qp.scale(scale, scale)
doc.drawContents(qp, QRectF(self.rect()))备注:
图形视图标签
这是一种完全不同的方法,因为它使用图形视图框架。诀窍是在场景中使用单个QGraphicsTextItem,让视图注意调整大小/对齐。
class GraphicsLabel(QGraphicsView):
def __init__(self, text=''):
super().__init__()
# graphics view usually have a background and a frame around them,
# let's remove both of them
self.setFrameShape(0)
self.setStyleSheet('background: transparent;')
# as most QAbstractScrollAreas, views have a default minimum size hint
# that makes them "bigger" whenever they're shown; let's ignore that
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
scene = QGraphicsScene(self)
self.setScene(scene)
self.textItem = scene.addText('')
self.setText(text)
def minimumSizeHint(self):
# this is related to the minimum size hint specified above
font = self.font()
font.setPointSize(1)
return QFontMetrics(font).boundingRect(self.textItem.toPlainText()).size()
def setText(self, text):
font = self.font()
font.setPointSize(1)
self.setMinimumSize(QFontMetrics(font).boundingRect(text).size())
if Qt.mightBeRichText(text):
self.textItem.setHtml(text)
else:
self.textItem.setPlainText(text)
doc = self.textItem.document()
frame = self.textItem.document().rootFrame().frameFormat()
if frame.margin():
frame.setMargin(0)
doc.rootFrame().setFrameFormat(frame)
self.textItem.setDocument(doc)
def text(self):
# provide a basic interface similar to a QLabel
return self.textItem.toPlainText()
def resizeEvent(self, event):
# the base class implementation is always required for QAbstractScrollArea
# descendants; then we resize its contents to fit its size.
super().resizeEvent(event)
self.fitInView(self.textItem, Qt.KeepAspectRatio)备注:
QWidget.setStyleSheet)图形视图QLabel小部件
这个方法与上面的方法非常相似,但是它没有创建一个简单的“文本项”,而是在图形场景中添加了一个实际的QLabel。
class GraphicsLabelWidget(QGraphicsView):
def __init__(self, text=''):
super().__init__()
self.setFrameShape(0)
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
self.setStyleSheet('background: transparent;')
scene = QGraphicsScene(self)
self.setScene(scene)
self.label = QLabel(text)
self.labelItem = scene.addWidget(self.label)
self.label.setStyleSheet(self.styleSheet())
self.setText(text)
def minimumSizeHint(self):
font = self.font()
font.setPointSize(1)
doc = QTextDocument()
if Qt.mightBeRichText(self.label.text()):
doc.setHtml(self.label.text())
else:
doc.setPlainText(self.label.text())
return QFontMetrics(font).boundingRect(self.label.text()).size()
def setText(self, text):
font = self.font()
font.setPointSize(1)
self.setMinimumSize(QFontMetrics(font).boundingRect(text).size())
self.label.setText(text)
def text(self):
return self.label.toPlainText()
def resizeEvent(self, event):
super().resizeEvent(event)
self.fitInView(self.labelItem, Qt.KeepAspectRatio)备注:
addText图形实现;同时,它也稍慢一些测试示例:
只为商品提供(添加上面的类以查看它的作用)。
class Demo(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout(self)
testText = 'PASS <b>bold</b><br/><i>new italic line</i><br/>{}'
resizeLabel = ResizeFontLabel(testText.format('resize mode'))
layout.addWidget(resizeLabel)
resizeLabel.setAlignment(Qt.AlignRight|Qt.AlignBottom)
paintLabel = PaintLabel(testText.format('paint mode'))
layout.addWidget(paintLabel)
paintLabel.setAlignment(Qt.AlignRight|Qt.AlignBottom)
graphicsLabel = GraphicsLabel(testText.format('graphicsview mode'))
layout.addWidget(graphicsLabel)
graphicsLabel.setAlignment(Qt.AlignRight|Qt.AlignBottom)
graphicsLabelWidget = GraphicsLabelWidget(testText.format('graphicsview mode'))
layout.addWidget(graphicsLabelWidget)
graphicsLabelWidget.setAlignment(Qt.AlignRight|Qt.AlignBottom)
graphicsLabelWidget.label.setStyleSheet('QLabel {background: green;}')
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
demo = Demo()
demo.show()
app.exec()https://stackoverflow.com/questions/58925364
复制相似问题