有没有办法让标签的字体大小动态调整到 PyQt5 中标签中的文本?

Posted

技术标签:

【中文标题】有没有办法让标签的字体大小动态调整到 PyQt5 中标签中的文本?【英文标题】:Is there a way to make the font size of a label dynamicly adjust to the text thats put in the label In PyQt5? 【发布时间】:2020-09-06 18:22:40 【问题描述】:

我通过 API 获取玩家的当前位置,我希望标签根据我要放入标签的文本长度调整其字体大小。

例如字符串“Bedwars 4v4v4v4”很合适:

但字符串“Beast vs. Hunters Insane”被切断了:

到目前为止,这是我的代码:

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(893, 492)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("../../technostalk icon.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        MainWindow.setAccessibleName("")
        MainWindow.setStyleSheet(
        "QMainWindow\n"
        "background-color: rgb(54, 57, 63);\n"
        ""
        )
        MainWindow.setUnifiedTitleAndToolBarOnMac(False)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(10, 10, 131, 91))
        self.groupBox.setStyleSheet("QGroupBox\n"
        "\n"
        "border: 1px solid rgb(32, 34, 37);\n"
        "color: rgb(249, 249, 255);\n"
        "margin-top: 0.5em;\n"
        "\n"
        "\n"
        "QGroupBox::title \n"
        "subcontrol-origin: margin;\n"
        "left: 10px;\n"
        "padding: 0 3px 0 3px;\n"
        ""
        )
        self.groupBox.setObjectName("groupBox")
        self.label = QtWidgets.QLabel(self.groupBox)
        self.label.setGeometry(QtCore.QRect(10, 10, 171, 51))
        self.label.setStyleSheet(
                "QLabel\n"
        "color: rgb(0, 255, 0);\n"
        ""
        )
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.groupBox)
        self.label_2.setGeometry(QtCore.QRect(10, 60, 101, 16))
        self.label_2.setStyleSheet("QLabel\n"
        "color: rgb(255, 255, 255);\n"
        ""
        )
        self.label_2.setObjectName("label_2")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(150, 10, 221, 91))
        self.groupBox_2.setStyleSheet(
        "QGroupBox\n"
        "\n"
        "border: 1px solid rgb(32, 34, 37);\n"
        "color: rgb(249, 249, 255);\n"
        "margin-top: 0.5em;\n"
        "\n"
        "\n"
        "QGroupBox::title \n"
        "subcontrol-origin: margin;\n"
        "left: 10px;\n"
        "padding: 0 3px 0 3px;\n"
        ""
        )
        self.groupBox_2.setObjectName("groupBox_2")
        self.label_3 = QtWidgets.QLabel(self.groupBox_2)
        self.label_3.setGeometry(QtCore.QRect(10, 10, 211, 51))
        self.label_3.setStyleSheet(
        "QLabel\n"
        "\n"
        "color: rgb(255, 255, 255);\n"
        "\n"
        ""
        )
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(self.groupBox_2)
        self.label_4.setGeometry(QtCore.QRect(10, 60, 181, 16))
        self.label_4.setStyleSheet(
                "QLabel\n"
        "color: rgb(255, 255, 255);\n"
        ""
        )
        self.label_4.setObjectName("label_4")
        MainWindow.setCentralWidget(self.centralwidget)

【问题讨论】:

您确定要更改字体大小吗?因为如果问题是标签没有完全显示,我相信它是,那么你的问题是你没有使用layout manager。通常不鼓励动态更改字体大小以适应特定大小,因为它非常慢,可能会产生递归,而且通常是出于错误的原因。 标签没有完全显示,因为分组框,我想要字体大小比例,以便所有内容都适合标签(或分组框)的边界 【参考方案1】:

前提。调整标签的字体大小以确保它适合其容器的宽度通常不是一个好主意,最重要的是因为相同的小部件具有不同的字体大小会使整个界面不连贯。不要小看这方面,因为它对用户体验非常重要。

此外,正如 cmets 中已经建议的那样,使用固定几何形状通常是一个非常糟糕的主意。虽然我可以理解游戏界面的具体情况,但这并不妨碍对容器小部件使用布局管理器。造成这种情况的主要原因是,您在计算机上(甚至在 Designer 中)看到的内容很少是用户在其屏幕上实际看到的内容,并且如果用户调整窗口大小(可能将其最大化甚至调整大小以适应较小的屏幕)你最终会看到一个丑陋甚至不可用的界面。 因此,我强烈建议您对整个界面使用布局管理器,并仅对某些子小部件(可能只有标签)使用固定几何图形。

在任何情况下,一个可能的解决方案是使用一个继承自 QLabel 的自定义类,并将设计器中的每个标签提升到该自定义类(在本文末尾有更多信息)。

这是一个自定义类的可能实现:

class CustomLabel(QtWidgets.QLabel):
    def adjustFont(self):
        if self.parent():
            # if the widget has a parent, get the available width by computing the
            # available rectangle between the parent rectangle and the widget
            # geometry (logical AND)
            rect = self.parent().rect() & self.geometry()
            width = rect.width()
        else:
            width = self.width()
        font = self.font()
        text = self.text()
        while True:
            # compute the text width with the current font size
            textWidth = QtGui.QFontMetrics(font).size(
                QtCore.Qt.TextSingleLine, text).width()
            # break if the width is enough to show the text or the font size is
            # sufficient to keep the text readable
            if textWidth <= width or font.pointSize() <= 6:
                break
            font.setPointSize(font.pointSize() - 1)
        self._font = font

    def setText(self, text):
        super().setText(text)
        self.adjustFont()

    def resizeEvent(self, event):
        self.adjustFont()

    def paintEvent(self, event):
        if self.text():
            qp = QtGui.QPainter(self)
            qp.setFont(self._font)
            qp.drawText(self.rect(), self.alignment(), self.text())
        else:
            super().paintEvent(event)

提升的小部件是一种使用自定义子类的方法,这些子类实现了继承类的特性以获得特殊功能。

要推广一个小部件,你必须右键单击它,选择“Promote to...”,在“Promoted class name”字段中插入类名,在“Header file”字段中插入包含该类的文件(作为python模块,所以如果类在文件“mylabel.py”中,插入“mylabel”),点击“添加”,然后点击“提升”。 添加新的提升的小部件类后,您可以通过从其上下文菜单的“提升到”子菜单中选择该提升的类来提升相同类型的其他小部件。

最后,请记住,您应该切勿修改pyuic 生成的文件,也不要试图模仿他们的行为(阅读更多关于using Designer 的信息),所以在设计器中推广标签,保存文件并使用pyuic再次生成它,然后创建一个包含以下代码的新脚本(在这种情况下,pyuic生成的文件名为mainWindow_ui.py):

from PyQt5 import QtCore, QtGui, QtWidgets
from mainWindow_ui import Ui_MainWindow

class CustomLabel(QtWidgets.QLabel):
# ... as the above example

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.label.setText('Short text')
        self.label_3.setText('Very very very very very very very very very long text')


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

【讨论】:

求详细解答!但是还有一个问题。在完整的应用程序中,我在不同的线程中使用各种 while 循环来获取有关播放器的信息并将其放入窗口中。在使用您为窗口提出的方式(Welp 我是德国人,您是否说 xD)时,我怎么能做到这一点。 我不确定我是否理解您的问题。我想你已经在使用self.somelabel.setText() 在游戏过程中更新标签,对吧?如果是这样,那就没什么可做的了,因为我已经为子类实现了setText(),它会自动计算相应的字体大小。 nvm 我可以将 MainWindow 类放入函数中并使函数成为线程。感谢您的帮助,明天我可以访问我的计算机时,我会尝试一切。再次感谢您的帮助:) @MergenStudios 不客气。请记住,如果您发现某个答案有用,您应该点赞(答案左侧的向上箭头),而如果该答案确实解决了您的问题,您应该通过单击复选标记将其标记为已接受。跨度> 好的我试过了,我得到一个错误在 pyuic5 生成的文件中我得到: ModuleNotFoundError: No module named 'AutoResizingLabel' 我用类 CustomLabel AutoResizingLabel 命名文件,我确保它全部在同一个文件,你知道我做错了什么吗?

以上是关于有没有办法让标签的字体大小动态调整到 PyQt5 中标签中的文本?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PyQt5 中保持行和列大小与网格布局相同?

PyQt5,让用户调整小部件的大小

在 sectionHeader 中自动调整字体大小

字体调整 HTML [重复]

根据标签长度调整从 xib 创建的视图大小

组合框没有正确调整大小以适应更大的字体大小