Search code examples
pythonmultithreadingpyqtpyqt4qthread

Background thread with QThread in PyQt


I have a program which interfaces with a radio I am using via a gui I wrote in PyQt. Obviously one of the main functions of the radio is to transmit data, but to do this continuously, I have to loop the writes, which causes the gui to hang. Since I have never dealt with threading, I tried to get rid of these hangs using QCoreApplication.processEvents(). The radio needs to sleep between transmissions, though, so the gui still hangs based on how long these sleeps last.

Is there a simple way to fix this using QThread? I have looked for tutorials on how to implement multithreading with PyQt, but most of them deal with setting up servers and are much more advanced than I need them to be. I honestly don't even really need my thread to update anything while it is running, I just need to start it, have it transmit in the background, and stop it.


Solution

  • I created a little example that shows 3 different and simple ways of dealing with threads. I hope it will help you find the right approach to your problem.

    import sys
    import time
    
    from PyQt5.QtCore import (QCoreApplication, QObject, QRunnable, QThread,
                              QThreadPool, pyqtSignal)
    
    
    # Subclassing QThread
    # http://qt-project.org/doc/latest/qthread.html
    class AThread(QThread):
    
        def run(self):
            count = 0
            while count < 5:
                time.sleep(1)
                print("A Increasing")
                count += 1
    
    # Subclassing QObject and using moveToThread
    # http://blog.qt.digia.com/blog/2007/07/05/qthreads-no-longer-abstract
    class SomeObject(QObject):
    
        finished = pyqtSignal()
    
        def long_running(self):
            count = 0
            while count < 5:
                time.sleep(1)
                print("B Increasing")
                count += 1
            self.finished.emit()
    
    # Using a QRunnable
    # http://qt-project.org/doc/latest/qthreadpool.html
    # Note that a QRunnable isn't a subclass of QObject and therefore does
    # not provide signals and slots.
    class Runnable(QRunnable):
    
        def run(self):
            count = 0
            app = QCoreApplication.instance()
            while count < 5:
                print("C Increasing")
                time.sleep(1)
                count += 1
            app.quit()
    
    
    def using_q_thread():
        app = QCoreApplication([])
        thread = AThread()
        thread.finished.connect(app.exit)
        thread.start()
        sys.exit(app.exec_())
    
    def using_move_to_thread():
        app = QCoreApplication([])
        objThread = QThread()
        obj = SomeObject()
        obj.moveToThread(objThread)
        obj.finished.connect(objThread.quit)
        objThread.started.connect(obj.long_running)
        objThread.finished.connect(app.exit)
        objThread.start()
        sys.exit(app.exec_())
    
    def using_q_runnable():
        app = QCoreApplication([])
        runnable = Runnable()
        QThreadPool.globalInstance().start(runnable)
        sys.exit(app.exec_())
    
    if __name__ == "__main__":
        #using_q_thread()
        #using_move_to_thread()
        using_q_runnable()