pythonpyqtpyqt5qlabelqpixmap

PyQt: How to prevent processing multiple resize events when maximizing a window?


I have a QMainWindow containing a child QWidget containing itself a QLabel.

When the window is maximized (e.g. by clicking the maximize icon on the window), the QLabel.resizeEvent() handler is called multiple times (supposedly to follow the progressive enlargement of the window until it takes the full desktop space).

The code in the event handler calls setPixmap() to scale the label pixmap. This is a relatively long operation which slows the process. Code for the label:

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QLabel, QFrame, QGridLayout
from PyQt5.QtGui import QImageReader, QPixmap

class DisplayArea(QLabel):
    def __init__(self):
        super().__init__()
        self.pix_map = None
        self.init_ui()

    def init_ui(self):
        self.setMinimumSize(1, 1)
        self.setStyleSheet("border:1px solid black;")

    def set_image(self, image):
        self.pix_map = QPixmap.fromImage(image)
        self.scale_image(self.size())

    def scale_image(self, size):
        if self.pix_map is None:
            return

        scaled = self.pix_map.scaled(size, Qt.KeepAspectRatio)
        self.setPixmap(scaled)

    def resizeEvent(self, e):
        self.scale_image(e.size())
        super().resizeEvent(e)

Is there a possibility to process the event only once, when the window has reached its final size?


Solution

  • The problem is that the resizeEvent is called many times in the time that the window is maximized, and that same number of times is what you call scale_image. One possible possible is not to update unless a period of time passes. In the following example only resizes for times greater than 100 ms (the time you must calibrate):

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class DisplayArea(QtWidgets.QLabel):
        def __init__(self):
            super().__init__()
            self.pix_map = QtGui.QPixmap()
            self._flag = False
            self.init_ui()
    
        def init_ui(self):
            self.setMinimumSize(1, 1)
            self.setStyleSheet("border:1px solid black;")
    
        def set_image(self, image):
            self.pix_map = QtGui.QPixmap.fromImage(image)
            self.scale_image()
    
        def scale_image(self):
            if self.pix_map.isNull():
                return
            scaled = self.pix_map.scaled(self.size(), QtCore.Qt.KeepAspectRatio)
            self.setPixmap(scaled)
    
        def resizeEvent(self, e):
            if not self._flag:
                self._flag = True
                self.scale_image()
                QtCore.QTimer.singleShot(100, lambda: setattr(self, "_flag", False))
            super().resizeEvent(e)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QMainWindow()
        da = DisplayArea()
        da.set_image(QtGui.QImage("logo.png"))
        w.setCentralWidget(da)
        w.show()
        sys.exit(app.exec_())