Automatically resizing label text in Qt - strange behaviour

reclosedev's answer gave me the key clue of using the Ignored size policy, but there were still a few details to iron out. Here's an example that calculates the font size that will fit in the label's current size.

from PySide2.QtGui import QResizeEvent, QFontMetrics, Qt
from PySide2.QtWidgets import QLabel


class ScaledLabel(QLabel):
    def resizeEvent(self, event: QResizeEvent):
        # This flag is used for pixmaps, but I thought it might be useful to
        # disable font scaling. Remove the check if you don't like it.
        if not self.hasScaledContents():
            return

        target_rect = self.contentsRect()
        text = self.text()

        # Use binary search to efficiently find the biggest font that will fit.
        max_size = self.height()
        min_size = 1
        font = self.font()
        while 1 < max_size - min_size:
            new_size = (min_size + max_size) // 2
            font.setPointSize(new_size)
            metrics = QFontMetrics(font)

            # Be careful which overload of boundingRect() you call.
            rect = metrics.boundingRect(target_rect, Qt.AlignLeft, text)
            if (rect.width() > target_rect.width() or
                    rect.height() > target_rect.height()):
                max_size = new_size
            else:
                min_size = new_size

        font.setPointSize(min_size)
        self.setFont(font)

Unfortunately, there are a few properties required to make this work when you use the scaled label. Either be sure to always set them, or override __init__() to make the defaults useful. Here's a working example that sets them:

from PySide2.QtCore import Qt
from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QSizePolicy, QLabel

from scaled_label import ScaledLabel


def main():
    app = QApplication()

    widget = QWidget()
    label1 = ScaledLabel('Lorem ipsum')
    label2 = ScaledLabel('Lorem ipsum')

    # Any policy other than Ignored will fight you when you resize.
    size_policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
    label1.setSizePolicy(size_policy)
    label2.setSizePolicy(size_policy)

    # If you check this flag, don't forget to set it.
    label1.setScaledContents(True)
    label2.setScaledContents(True)

    # "Ignored" policy means you have to define your own minimum size.
    label1.setMinimumSize(200, 40)
    label2.setMinimumSize(50, 10)

    # Standard label attributes still work.
    label1.setAlignment(Qt.AlignBottom)
    label2.setAlignment(Qt.AlignTop)

    # Tell the layout to scale the two fields at different sizes.
    layout = QVBoxLayout(widget)
    layout.addWidget(label1)
    layout.addWidget(label2)
    layout.setStretch(0, 4)
    layout.setStretch(1, 1)

    widget.show()
    exit(app.exec_())


main()

I think problem with resizing caused by SizePolicy. Try to set label's size policy to Ignored it should help.

label.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

Is this the correct approach to achieve this effect?

Probably yes, quick search in documentation gave no better solutions. But I would create subclass of QLabel, and do policy setup and resizing there. Example:

class StretchedLabel(QLabel):
    def __init__(self, *args, **kwargs):
        QLabel.__init__(self, *args, **kwargs)
        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

    def resizeEvent(self, evt):
        font = self.font()
        font.setPixelSize(self.height() * 0.8)
        self.setFont(font)

In case you need to fit text not only by height, but by width too, some aditional code required.