首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何获取给定矩形的QLabel字体信息?

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

Stack Overflow用户
提问于 2019-11-19 01:28:49
回答 1查看 993关注 0票数 0

我试图得到QLabel的字体大小,文本填充整个QLabel的矩形,我尝试使用QFontMetrics来获取,但是QFontMetrics不能通过给定的矩形获得字体大小?

例子:

当调整窗口大小时,GUI可能会卡住。

代码语言:javascript
复制
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()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-19 06:12:51

不要这样做

有几十个原因,你想要达到的是简单的错误。

最重要的是处理文本绘图,其大小是而不是,这是一项轻松的任务;此外,Qt使用标签内容来告诉窗口布局它可以拥有的大小、希望拥有的大小以及最重要的是它应该拥有的最小大小;所有这些对于GUI来说都是非常重要的,因为为了正确调整界面的所有其他元素,会考虑到这些内容。

最后,所有这些因素都基于标签的文本及其格式,这可能取决于文本内容和文本可能是“富文本”的事实(包括多字体大小和权重)。

如果您真的很清楚上面解释的概念,下面是4种可能的实现。它们都部分支持丰富的文本(字体权重、文本颜色等,但不支持真正的文本对齐)。

调整字体标签

虽然子类化QLabel似乎是最简单的方法,但实际上并非如此,因为它是一个比看起来复杂得多的小部件(正如我前面写的,处理文本小部件并不是一项容易的任务)

这种方法最重要的缺点是它非常慢,因为它必须仔细计算每次调整大小时的字体大小。虽然可以通过更好的实现来实现一些改进,但我还是不建议使用这种方法。

代码语言:javascript
复制
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()。他们的逻辑是非常重要的
  • 这种方法是slow
  • 它不支持文本对齐(至少在这个基本实现中是如此)

基于绘画的字体标签

该方法是对上述方法的简化。它不计算字体大小,但只绘制缩放到大小的内容。

代码语言:javascript
复制
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上计算它们会使这个过程变得非常复杂和缓慢。)

图形视图标签

这是一种完全不同的方法,因为它使用图形视图框架。诀窍是在场景中使用单个QGraphicsTextItem,让视图注意调整大小/对齐。

代码语言:javascript
复制
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。

代码语言:javascript
复制
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图形实现;同时,它也稍慢一些
  • 更好地支持样式表(但它们应该应用于实际的子标签)

测试示例:

只为商品提供(添加上面的类以查看它的作用)。

代码语言:javascript
复制
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()
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58925364

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档