Background thread with QThread in PyQt

后端 未结 6 1155
忘掉有多难
忘掉有多难 2020-11-22 05:39

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 co

6条回答
  •  一向
    一向 (楼主)
    2020-11-22 06:10

    Based on the Worker objects methods mentioned in other answers, I decided to see if I could expand on the solution to invoke more threads - in this case the optimal number the machine can run and spin up multiple workers with indeterminate completion times. To do this I still need to subclass QThread - but only to assign a thread number and to 'reimplement' the signals 'finished' and 'started' to include their thread number.

    I've focused quite a bit on the signals between the main gui, the threads, and the workers.

    Similarly, others answers have been a pains to point out not parenting the QThread but I don't think this is a real concern. However, my code also is careful to destroy the QThread objects.

    However, I wasn't able to parent the worker objects so it seems desirable to send them the deleteLater() signal, either when the thread function is finished or the GUI is destroyed. I've had my own code hang for not doing this.

    Another enhancement I felt was necessary was was reimplement the closeEvent of the GUI (QWidget) such that the threads would be instructed to quit and then the GUI would wait until all the threads were finished. When I played with some of the other answers to this question, I got QThread destroyed errors.

    Perhaps it will be useful to others. I certainly found it a useful exercise. Perhaps others will know a better way for a thread to announce it identity.

    #!/usr/bin/env python3
    #coding:utf-8
    # Author:   --<>
    # Purpose:  To demonstrate creation of multiple threads and identify the receipt of thread results
    # Created: 19/12/15
    
    import sys
    
    
    from PyQt4.QtCore import QThread, pyqtSlot, pyqtSignal
    from PyQt4.QtGui import QApplication, QLabel, QWidget, QGridLayout
    
    import sys
    import worker
    
    class Thread(QThread):
        #make new signals to be able to return an id for the thread
        startedx = pyqtSignal(int)
        finishedx = pyqtSignal(int)
    
        def __init__(self,i,parent=None):
            super().__init__(parent)
            self.idd = i
    
            self.started.connect(self.starttt)
            self.finished.connect(self.finisheffffd)
    
        @pyqtSlot()
        def starttt(self):
            print('started signal from thread emitted')
            self.startedx.emit(self.idd) 
    
        @pyqtSlot()
        def finisheffffd(self):
            print('finished signal from thread emitted')
            self.finishedx.emit(self.idd)
    
    class Form(QWidget):
    
        def __init__(self):
            super().__init__()
    
            self.initUI()
    
            self.worker={}
            self.threadx={}
            self.i=0
            i=0
    
            #Establish the maximum number of threads the machine can optimally handle
            #Generally relates to the number of processors
    
            self.threadtest = QThread(self)
            self.idealthreadcount = self.threadtest.idealThreadCount()
    
            print("This machine can handle {} threads optimally".format(self.idealthreadcount))
    
            while i 

    And the worker code below

    #!/usr/bin/env python3
    #coding:utf-8
    # Author:   --<>
    # Purpose:  Stack Overflow
    # Created: 19/12/15
    
    import sys
    import unittest
    
    
    from PyQt4.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
    import time
    import random
    
    
    class Worker(QObject):
        finished = pyqtSignal(int)
        intReady = pyqtSignal(int,int)
    
        def __init__(self, i=0):
            '''__init__ is called while the worker is still in the Gui thread. Do not put slow or CPU intensive code in the __init__ method'''
    
            super().__init__()
            self.idd = i
    
    
    
        @pyqtSlot()
        def procCounter(self): # This slot takes no params
            for j in range(1, 10):
                random_time = random.weibullvariate(1,2)
                time.sleep(random_time)
                self.intReady.emit(j,self.idd)
                print('Worker {0} in thread {1}'.format(self.idd, self.thread().idd))
    
            self.finished.emit(self.idd)
    
    
    if __name__=='__main__':
        unittest.main()
    

提交回复
热议问题