我正在尝试获取文本填充整个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()
您想实现的很多原因都是错误的。最重要的是,处理文本绘图及其大小是一件容易的事。同样,Qt使用标签内容告诉窗口布局它可能的大小,想要的大小,最重要的是它应该具有的最小大小;所有这些对于GUI都是非常重要的,因为为了正确调整界面的其他元素的大小,将考虑到这一点。最后,所有这些因素均基于标签的文本及其格式,这可能取决于文本内容以及该文本可能是“富文本”(包括多种字体大小和粗细)的事实。如果您确实意识到上述概念,那么这里有4种可能的实现。它们全部[[partially
支持富文本(字体粗细,文本颜色等,但不支持真实文本对齐)。虽然子类化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具有一定的边距,并且标签中未使用该边距。
请注意
or/and
方法中的不同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()))
注意:
比第一种方法快
不支持对齐
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
)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()