如何获得给定矩形的QLabel字体信息?

问题描述 投票:0回答:1

我正在尝试获取文本填充整个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()
python pyqt pyqt5
1个回答
0
投票

不做

您想实现的很多原因都是错误的。最重要的是,处理文本绘图及其大小是一件容易的事。同样,Qt使用标签内容告诉窗口布局它可能的大小,想要的大小,最重要的是它应该具有的最小大小;所有这些对于GUI都是非常重要的,因为为了正确调整界面的其他元素的大小,将考虑到这一点。最后,所有这些因素均基于标签的文本及其格式,这可能取决于文本内容以及该文本可能是“富文本”(包括多种字体大小和粗细)的事实。如果您确实意识到上述概念,那么这里有4种可能的实现。它们全部[[partially

支持富文本(字体粗细,文本颜色等,但不支持真实文本对齐)。

Label test examples调整字体标签的大小

虽然子类化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()。他们的逻辑很重要

此方法为

  • 它不支持文本对齐(至少在此基本实现中)
  • 基于绘画的字体标签
  • 此方法是上述方法的简化。它不计算字体大小,而只是将内容
  • scaled
绘制为大小。

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()))

注意:

比第一种方法快

不支持对齐

    由于缩放比例未考虑字体大小,因此文本将不会尽可能大(这是由于QTextDocument可以具有多个“文本块”,因此在每个paintEvent上计算它们会使其变得非常复杂且缓慢]
  • 图形视图标签
  • 这是一种完全不同的方法,因为它使用了Graphics View Framework。诀窍是在场景中使用单个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样式(通过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()
    © www.soinside.com 2019 - 2024. All rights reserved.