Search code examples
pythonanimationpyqt5qpropertyanimation

Animating FontSize of a QLabel in PyQt5


I wanted to ask if we could just animate the fontsize of the QLabel in PyQt5 with QPropertyAnimation.

I tried by adding QPropertyAnimation(self.label , b"fontSize") but It was not working and I got the warning

I want you increase the text of the QLabel and then again switch to normal size


Solution

  • From the QPropertyAnimation description:

    QPropertyAnimation interpolates over Qt properties. As property values are stored in QVariants, the class inherits QVariantAnimation, and supports animation of the same meta types as its super class.

    A class declaring properties must be a QObject. To make it possible to animate a property, it must provide a setter (so that QPropertyAnimation can set the property's value).

    All classes that inherit from QObject (including widgets) support Qt properties, and in fact most of them have "builtin" properties, but, obviously, not all properties support animations: they must be based on numeric values. You can animate a numeric change (eg: from 0 to 100), not a text (eg. from 'ABC' to 'PYZ').

    For instance, all QWidget have a pos property, and since such property (which is a QPoint) is based on numbers, you can create an animation. You can see the list of supported variant types for animations in the QVariantAnimation docs. Consider that all documentation pages regarding QObject subclasses contain a property section (see the QWidget properties for example), and that properties obviously are inherited from their super classes.

    There is no property for the font size, though, so there are two possibilities:

    1. create a custom property (by using the pyqtProperty decorator in PyQt);
    2. use a QVariantAnimation, which is not bound to any property;

    Depending on the situation, one might prefer one approach or the other, but for this specific case it doesn't change that much; the QVariantAnimation is certainly simpler, the Qt property approach is more "compliant".

    Here you can see how the property is created using the pyqtProperty decorator. Since the animation writes the property, having a setter is mandatory.

    class AnimationTest(QtWidgets.QWidget):
        def __init__(self):
            super().__init__()
            self.startButton = QtWidgets.QPushButton('Start')
            self.label = QtWidgets.QLabel('Hello!')
            self.labelFont = self.font()
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(self.startButton)
            layout.addWidget(self.label)
    
            self.ani = QtCore.QPropertyAnimation(self, b'labelFontSize')
            self.ani.setStartValue(10)
            self.ani.setEndValue(80)
            self.ani.setDuration(1500)
    
            self.startButton.clicked.connect(self.ani.start)
    
        @QtCore.pyqtProperty(int)
        def labelFontSize(self):
            return self.labelFont.pointSize()
    
        @labelFontSize.setter
        def labelFontSize(self, size):
            self.labelFont.setPointSize(size)
            self.label.setFont(self.labelFont)
    
    
    import sys
    app = QtWidgets.QApplication(sys.argv)
    test = AnimationTest()
    test.show()
    sys.exit(app.exec_())
    

    The variant animation is certainly shorter:

    class AnimationTest(QtWidgets.QWidget):
        def __init__(self):
            # ...
            self.ani = QtCore.QVariantAnimation()
            self.ani.setStartValue(10)
            self.ani.setEndValue(80)
            self.ani.setDuration(1500)
            self.ani.valueChanged.connect(self.updateLabelFont)
    
            self.startButton.clicked.connect(self.ani.start)
    
        def updateLabelFont(self, value):
            self.labelFont.setPointSize(value)
            self.label.setFont(self.labelFont)
    

    Please consider that font size animations are often problematic, as most fonts have slightly different glyphs and spacings depending on the size. In the examples above I used a pretty long animation that will probably show the effect: while the size increases linearly, the change in the font usually is not very smooth.