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. How to schedule a function to run on the main UI thread?
Forum Updated to NodeBB v4.3 + New Features

How to schedule a function to run on the main UI thread?

Scheduled Pinned Locked Moved Unsolved Qt for Python
3 Posts 2 Posters 2.2k 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.
  • R Offline
    R Offline
    relent95
    wrote on last edited by relent95
    #1

    I want a worker thread created by the standard threading module to interact with the main UI thread, by scheduling a function on the worker thread, where that function manipulates widgets and will be run on the main UI thread.(Like Gdk.threads_add_idle() in GTK or runOnUiThread() in Android)

    There are plenty of articles on QThread and they suggest defining a class with custom signals, customized for each specific problem. But I don't want that pattern. I want a reusable pattern, which separates the worker and UI implementations as much as possible.

    I came to a solution like the following, that sends dummy signals to a global dummy QObject.

    import sys
    import time
    import threading
    from PySide2.QtCore import *
    from PySide2.QtWidgets import *
    
    class IdleRunner(QObject):
        run = Signal(object, tuple, float)
        def __init__(self):
            super().__init__()
            self.run.connect(self.on_run)
        def on_run(self, func, args, delay):
            if delay: QTimer.singleShot(delay * 1000, lambda: func(*args))
            else: func(*args)
    _idle_runner = IdleRunner()
    def run_on_idle(func, *args, delay = 0):
        _idle_runner.run.emit(func, args, delay)
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__(windowTitle = sys.argv[0])
            self.resize(400, 300)
            self.setAttribute(Qt.WA_DeleteOnClose, True)
    
            self.label = label = QLabel('aaa', alignment = Qt.AlignCenter)
            self.setCentralWidget(label)
    
            def thread_entry():
                time.sleep(1)
                run_on_idle(lambda: self.label.setText('bbb'))
                run_on_idle(self.close, delay = 1)
            self.thread = thread = threading.Thread(target = thread_entry)
            thread.start()
        def close(self):
            self.thread.join()
            super().close()
    
    app = QApplication()
    main_window = MainWindow()
    main_window.show()
    app.exec_()
    

    I have two questions.

    1. What is the best solution to this?(I expects a more elegant one in a Qt way.)
    2. What are the possible problems of this solution? (Such as a memory leak or a runtime overhead).
    jsulmJ 1 Reply Last reply
    0
    • R relent95

      I want a worker thread created by the standard threading module to interact with the main UI thread, by scheduling a function on the worker thread, where that function manipulates widgets and will be run on the main UI thread.(Like Gdk.threads_add_idle() in GTK or runOnUiThread() in Android)

      There are plenty of articles on QThread and they suggest defining a class with custom signals, customized for each specific problem. But I don't want that pattern. I want a reusable pattern, which separates the worker and UI implementations as much as possible.

      I came to a solution like the following, that sends dummy signals to a global dummy QObject.

      import sys
      import time
      import threading
      from PySide2.QtCore import *
      from PySide2.QtWidgets import *
      
      class IdleRunner(QObject):
          run = Signal(object, tuple, float)
          def __init__(self):
              super().__init__()
              self.run.connect(self.on_run)
          def on_run(self, func, args, delay):
              if delay: QTimer.singleShot(delay * 1000, lambda: func(*args))
              else: func(*args)
      _idle_runner = IdleRunner()
      def run_on_idle(func, *args, delay = 0):
          _idle_runner.run.emit(func, args, delay)
      
      class MainWindow(QMainWindow):
          def __init__(self):
              super().__init__(windowTitle = sys.argv[0])
              self.resize(400, 300)
              self.setAttribute(Qt.WA_DeleteOnClose, True)
      
              self.label = label = QLabel('aaa', alignment = Qt.AlignCenter)
              self.setCentralWidget(label)
      
              def thread_entry():
                  time.sleep(1)
                  run_on_idle(lambda: self.label.setText('bbb'))
                  run_on_idle(self.close, delay = 1)
              self.thread = thread = threading.Thread(target = thread_entry)
              thread.start()
          def close(self):
              self.thread.join()
              super().close()
      
      app = QApplication()
      main_window = MainWindow()
      main_window.show()
      app.exec_()
      

      I have two questions.

      1. What is the best solution to this?(I expects a more elegant one in a Qt way.)
      2. What are the possible problems of this solution? (Such as a memory leak or a runtime overhead).
      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @relent95 said in How to schedule a function to run on the main UI thread?:

      by scheduling a function manipulating widgets inside the worker thread entry

      Manipulating UI from different threads than GUI thread is not supported!
      Normal way in Qt to communicate between threads are signals/slots. If you want to notify main thread from another thread implement and emit a signal in that other thread. Connect this signal to a slot in main thread.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      R 1 Reply Last reply
      0
      • jsulmJ jsulm

        @relent95 said in How to schedule a function to run on the main UI thread?:

        by scheduling a function manipulating widgets inside the worker thread entry

        Manipulating UI from different threads than GUI thread is not supported!
        Normal way in Qt to communicate between threads are signals/slots. If you want to notify main thread from another thread implement and emit a signal in that other thread. Connect this signal to a slot in main thread.

        R Offline
        R Offline
        relent95
        wrote on last edited by
        #3

        @jsulm Thanks for a quick reply. I didn't mean to manipulate UI directly in the worker thread, but schedule a function that does that. I'll update my question to be more clear.

        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