Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Defer Resize Event due to expensive resize method.

Defer Resize Event due to expensive resize method.

Scheduled Pinned Locked Moved Unsolved Qt for Python
5 Posts 3 Posters 189 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    AliSot2000
    wrote on 2 Apr 2025, 13:50 last edited by
    #1

    Hi there

    I wanted to check that I've correctly identified a dead end in my development. The main point is this: I have an application that has a table which contains a lot of images (~a few hundereds) and when you perform a resizeEvent, the GUI lags a bit.

    To prevent that from happening, I've added a QTimer, that is triggered by the resize event and only once the timer exits, the resize action is performed. However, it is possible for the timer to trigger, even when you're still resizing. As soon as the mouse stops moving, there are no longer resizeEvents emitted which causes the timer to exit and trigger a resize.

    I've already set the timeout to the more conservative side of about 500ms but I find it a bit annoying that I have to rely on timers and heuristics when I could (!) possibly do it differently.

    I've tinkered around with different solutions, looked at questions on this and other forums and also asked ChatGPT but the problem seems to be the following.
    The resizing of the MainWindow in conjunction with the detecting the mousePressEvent for resizing Windows is happening in the Desktop Environemnt. When I'm trying to access the pressed mouse buttons during the ResizeEvent, they are reported as not pressed. I assume the mouseDown on the resize trigger of the Windows is handled in the Desktop Environment and the resizing of the Window then triggeres a ResizeEvent in the QT Application but the application is never "sees" the mouse doing anything.

    Is there a way to detect if the LMB is pressed during a ResizeEvent? Because it doesn't seem to be the case.

    Here's a simple example to test:

    from PyQt6.QtCore import Qt, QSize
    from PyQt6.QtGui import QResizeEvent
    from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
    
    
    class DelayedLabel(QLabel):
        perform_resize: bool = False
    
        def resizeEvent(self, a0):
            """
            Handle resize event
            """
            if self.perform_resize:
                super().resizeEvent(a0)
    
    
    class CustomMainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
    
            self.table_widget = DelayedLabel()
            self.setCentralWidget(self.table_widget)
    
            self.resize_event_buffer_old = None
            self.resize_event_buffer_new = None
            self.last_resize_event = None
    
        def resizeEvent(self, a0):
            """
            Custom handling of Resize Event
            """
            if not self.table_widget.perform_resize:
                self.resize_event_buffer_old = QSize(a0.oldSize())
                self.resize_event_buffer_new = QSize(a0.size())
    
            application = QApplication.instance()
            print(application.mouseButtons())
    
        def mousePressEvent(self, a0):
            """
            Check it's a LMB event
            """
            # Left button is down, means we don't update the widget
            if a0.button() == Qt.MouseButton.LeftButton:
                self.table_widget.perform_resize = False
                print(f"Mouse Pressed")
    
        def mouseReleaseEvent(self, a0):
            """
            Check it's a LMB event'
            """
            # Left button is up, means we do update the widget
            if a0.button() == Qt.MouseButton.LeftButton:
                self.table_widget.perform_resize = True
                print(f"Mouse Released")
    
                # Submit the event again
                if self.resize_event_buffer_new is not None and self.resize_event_buffer_old is not None:
                    print(f"Sending Custom Event")
                    new_event = QResizeEvent(self.resize_event_buffer_new, self.resize_event_buffer_old)
                    self.table_widget.resizeEvent(new_event)
    
                    self.resize_event_buffer_new = self.resize_event_buffer_old = None
    
    
    if __name__ == "__main__":
        app = QApplication([])
        window = CustomMainWindow()
        window.show()
        app.exec()
    
    

    You should observe that when pressing on on the trigger for resizing, nothing happens and when you release after having resized the window also nothing happens.

    S 1 Reply Last reply 3 Apr 2025, 06:40
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 2 Apr 2025, 21:26 last edited by
      #2

      Hi and welcome to devnet,

      Did you already consider using the updates enabled properly ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      A 1 Reply Last reply 26 days ago
      1
      • A AliSot2000
        2 Apr 2025, 13:50

        Hi there

        I wanted to check that I've correctly identified a dead end in my development. The main point is this: I have an application that has a table which contains a lot of images (~a few hundereds) and when you perform a resizeEvent, the GUI lags a bit.

        To prevent that from happening, I've added a QTimer, that is triggered by the resize event and only once the timer exits, the resize action is performed. However, it is possible for the timer to trigger, even when you're still resizing. As soon as the mouse stops moving, there are no longer resizeEvents emitted which causes the timer to exit and trigger a resize.

        I've already set the timeout to the more conservative side of about 500ms but I find it a bit annoying that I have to rely on timers and heuristics when I could (!) possibly do it differently.

        I've tinkered around with different solutions, looked at questions on this and other forums and also asked ChatGPT but the problem seems to be the following.
        The resizing of the MainWindow in conjunction with the detecting the mousePressEvent for resizing Windows is happening in the Desktop Environemnt. When I'm trying to access the pressed mouse buttons during the ResizeEvent, they are reported as not pressed. I assume the mouseDown on the resize trigger of the Windows is handled in the Desktop Environment and the resizing of the Window then triggeres a ResizeEvent in the QT Application but the application is never "sees" the mouse doing anything.

        Is there a way to detect if the LMB is pressed during a ResizeEvent? Because it doesn't seem to be the case.

        Here's a simple example to test:

        from PyQt6.QtCore import Qt, QSize
        from PyQt6.QtGui import QResizeEvent
        from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
        
        
        class DelayedLabel(QLabel):
            perform_resize: bool = False
        
            def resizeEvent(self, a0):
                """
                Handle resize event
                """
                if self.perform_resize:
                    super().resizeEvent(a0)
        
        
        class CustomMainWindow(QMainWindow):
            def __init__(self):
                super().__init__()
        
                self.table_widget = DelayedLabel()
                self.setCentralWidget(self.table_widget)
        
                self.resize_event_buffer_old = None
                self.resize_event_buffer_new = None
                self.last_resize_event = None
        
            def resizeEvent(self, a0):
                """
                Custom handling of Resize Event
                """
                if not self.table_widget.perform_resize:
                    self.resize_event_buffer_old = QSize(a0.oldSize())
                    self.resize_event_buffer_new = QSize(a0.size())
        
                application = QApplication.instance()
                print(application.mouseButtons())
        
            def mousePressEvent(self, a0):
                """
                Check it's a LMB event
                """
                # Left button is down, means we don't update the widget
                if a0.button() == Qt.MouseButton.LeftButton:
                    self.table_widget.perform_resize = False
                    print(f"Mouse Pressed")
        
            def mouseReleaseEvent(self, a0):
                """
                Check it's a LMB event'
                """
                # Left button is up, means we do update the widget
                if a0.button() == Qt.MouseButton.LeftButton:
                    self.table_widget.perform_resize = True
                    print(f"Mouse Released")
        
                    # Submit the event again
                    if self.resize_event_buffer_new is not None and self.resize_event_buffer_old is not None:
                        print(f"Sending Custom Event")
                        new_event = QResizeEvent(self.resize_event_buffer_new, self.resize_event_buffer_old)
                        self.table_widget.resizeEvent(new_event)
        
                        self.resize_event_buffer_new = self.resize_event_buffer_old = None
        
        
        if __name__ == "__main__":
            app = QApplication([])
            window = CustomMainWindow()
            window.show()
            app.exec()
        
        

        You should observe that when pressing on on the trigger for resizing, nothing happens and when you release after having resized the window also nothing happens.

        S Offline
        S Offline
        SimonSchroeder
        wrote on 3 Apr 2025, 06:40 last edited by
        #3

        @AliSot2000 said in Defer Resize Event due to expensive resize method.:

        Is there a way to detect if the LMB is pressed during a ResizeEvent? Because it doesn't seem to be the case.

        Most likely resizing a (top-level) window is done by the underlying OS/window manager and thus Qt does not know anything about the mouse. This is why you only a resize event, but no mouse event. (At least, that is my guess.)

        There is a common trick using two timers, though the second timer is usually used to not delay the function call indefinitely (which you don't seem to need in your case). So, using a single timer is okay. However, you need to make sure that you reuse the same timer and reset it, so that the timeout is further delayed until there no more interactions.

        A 1 Reply Last reply 26 days ago
        0
        • S SGaist
          2 Apr 2025, 21:26

          Hi and welcome to devnet,

          Did you already consider using the updates enabled properly ?

          A Offline
          A Offline
          AliSot2000
          wrote 26 days ago last edited by
          #4

          @SGaist

          I've looked up your suggestion, however I fail to see how this would solve my problem.

          I'm guessing that you'd disable the widget once you start receiving ResizeEvents and then enable it after a delay [...].

          But as far as I can tell, this suggestion still has the same problem. I cannot detect when the Window is "done resizing" by the MoseReleaseEvent or if the LMB is pressed.

          1 Reply Last reply
          0
          • S SimonSchroeder
            3 Apr 2025, 06:40

            @AliSot2000 said in Defer Resize Event due to expensive resize method.:

            Is there a way to detect if the LMB is pressed during a ResizeEvent? Because it doesn't seem to be the case.

            Most likely resizing a (top-level) window is done by the underlying OS/window manager and thus Qt does not know anything about the mouse. This is why you only a resize event, but no mouse event. (At least, that is my guess.)

            There is a common trick using two timers, though the second timer is usually used to not delay the function call indefinitely (which you don't seem to need in your case). So, using a single timer is okay. However, you need to make sure that you reuse the same timer and reset it, so that the timeout is further delayed until there no more interactions.

            A Offline
            A Offline
            AliSot2000
            wrote 26 days ago last edited by
            #5

            @SimonSchroeder

            I think I'm already doing what you're suggesting.

            I've implemented a custom resizeEvent(...) that calls timer.start() on a single shot timer every time a ResizeEvent is recieved. This also resets the timer if an event is received shortly after another.

            And then I perform the actual resize of the widget when the timer times out.

            ChatGPT Suggested using this:

            import sys
            from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
            from PyQt6.QtCore import QTimer, QAbstractNativeEventFilter
            from PyQt6.QtGui import QGuiApplication
            
            class NativeResizeFilter(QAbstractNativeEventFilter):
                """Listens for native window events to detect when resizing stops."""
                
                def __init__(self, callback):
                    super().__init__()
                    self.callback = callback  # Function to call when resize stops
            
                def nativeEventFilter(self, eventType, message):
                    from ctypes import windll
                    if eventType == "windows_generic_MSG":
                        msg = int.from_bytes(message[:8], byteorder=sys.byteorder)
                        WM_EXITSIZEMOVE = 0x0232  # Windows event when resizing stops
                        if msg == WM_EXITSIZEMOVE:
                            self.callback()
                    return False, 0
            

            It seems (!) to be potentially possible to do the deferred scaling using events on Windows.

            I've also looked into dealing with NativeEvents on MacOS and Linux however, it seems to be rather tedious.

            So as for now, I've opted to go with the timer and maybe do the fancy resizing if I have the time to spare.

            AliSot2000

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved