Search code examples
pythonpython-3.xpyqt5qthread

Passing data from a QThread to another QThread


I have a situation where a Gui is active and a QThread. The QThread is getting and saving data in the background all the time, it should not stop doing this. Now I want to process the latest data from the QThread without interrupting the QThread or freezing the Gui.

So I think I need another thread to do this?! How can I pass its data to another thread and do something with it?

import sys, random, time
from PyQt5 import QtWidgets
from PyQt5.QtCore import  *


class Ui(QtWidgets.QMainWindow):
    def __init__(self):
        super(Ui, self).__init__()
        self.setWindowTitle('Window')

        #getData
        self.myGetData = getData()
        self.myGetData.start()

        self.show()

class getData(QThread):
    #This Thread should run all the time
    def run(self):
        while True:
            myNumber = random.randint(0, 100)
            #He 'processData Thread'!! Do Something with mynumber!!
            time.sleep(1)

class processData(QThread):
    def processNumber(self, myNumber):
        #Extremly complex code will execute while 'getData' is doing its thing.
        newNumber = myNumber * 10
        return newNumber

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = Ui()
    sys.exit(app.exec_())

Found a lot of examples on how to pass data from a QThread to the interface (signals).. But not the other way around. The signals are confusing me a bit in this case..


Solution

  • I would like to propose do next:

    import sys, random, time
    from PyQt5 import QtWidgets
    from PyQt5.QtCore import  *
    
    from PyQt5 import Qt          #+
    
    class getData(QThread):
        #This Thread should run all the time
    
        threadSignalGetData = pyqtSignal(int)
        def __init__(self, myNumber):
            super().__init__()
            self.myNumber = myNumber
    
        def run(self):
            #myNumber = 0
            while True:
                #He 'processData Thread'!! Do Something with mynumber!!
                Qt.QThread.msleep(1000)
                self.myNumber += 1
                self.threadSignalGetData.emit(self.myNumber)
    
    class MsgBoxGetData(Qt.QDialog):
        def __init__(self):
            super().__init__()
    
            layout     = Qt.QVBoxLayout(self)
            self.label = Qt.QLabel("")
            layout.addWidget(self.label)
    
            close_btn  = Qt.QPushButton("Close window GetData")
            layout.addWidget(close_btn)
    
            close_btn.clicked.connect(self.close) 
    
            self.setGeometry(900, 65, 400, 80)
            self.setWindowTitle('MsgBox GetData')
            self.setStyleSheet("""QLabel{
              font-family:'Consolas'; 
              color: green; 
              font-size: 16px;}""")
    
    
    class processData(QThread):
    
        threadSignalProcessData = pyqtSignal(int, int)
        def __init__(self, myNumber):
            super().__init__()
            self.newNumber = myNumber
    
        def run(self):
            flagProcessData = True
            while flagProcessData:
                #Extremly complex code will execute while 'getData' is doing its thing.
                newNumber = self.newNumber * 10
                self.threadSignalProcessData.emit(self.newNumber, newNumber)
                flagProcessData = False
    
    class MsgBoxProcessData(Qt.QDialog):
        def __init__(self):
            super().__init__()
    
            layout     = Qt.QVBoxLayout(self)
            self.label = Qt.QLabel("")
            layout.addWidget(self.label)
    
            close_btn  = Qt.QPushButton("Close window ProcessData")
            layout.addWidget(close_btn)
    
            close_btn.clicked.connect(self.close) 
    
            self.setGeometry(900, 200, 400, 80)
            self.setWindowTitle('MsgBox ProcessData')            
            self.setStyleSheet("""QLabel{
              font-family:'Consolas'; 
              color: red; 
              font-size: 24px;}""")            
    
    
    class Ui(Qt.QWidget):
        def __init__(self, parent=None):
            super(Ui, self).__init__(parent)
    
            layout   = Qt.QVBoxLayout(self)
            self.lbl = Qt.QLabel("process GUI")
            layout.addWidget(self.lbl)
            self.btnA = Qt.QPushButton("Start getData")
            layout.addWidget(self.btnA)
            self.btnB = Qt.QPushButton("Start processData")
            layout.addWidget(self.btnB)        
    
            self.setGeometry(550, 65, 300, 300)
            self.setWindowTitle('Window')
    
    
            self.btnA.clicked.connect(self.usingGetData)
            self.btnB.clicked.connect(self.usingProcessData)
    
            self.myNumber  = 0
            self.newNumber = None
            self.msgGetData    = MsgBoxGetData()  
            self.threadGetData = None
            self.msgProcessData    = MsgBoxProcessData()
            self.threadProcessData = None
    
    
            self.counter = 0
            self.timer = Qt.QTimer()
            self.timer.setInterval(1000)
            # -------- timeout -------> def recurring_timer(self):
            self.timer.timeout.connect(self.recurring_timer)   
            self.timer.start()
    
            self.setStyleSheet("""QLabel{
              font-family:'Consolas'; 
              color: blue; 
              font-size: 20px;}""")
    
    
            self.show()
    
        def recurring_timer(self):
            self.counter += 1
            self.lbl.setText("process GUI: %d" % self.counter)         
    
        # ---- getData(QThread) -----------------------------------------------------#    
        def usingGetData(self):
            if self.threadGetData is None:
                self.threadGetData = getData(self.myNumber) 
                self.threadGetData.threadSignalGetData.connect(self.on_threadSignalGetData)
                self.threadGetData.finished.connect(self.finishedGetData)
                self.threadGetData.start()
                self.btnA.setText("Stop getData(QThread)")
            else:
                self.threadGetData.terminate()         
                self.threadGetData = None
                self.btnA.setText("Start getData(QThread)")    
    
        def finishedGetData(self):
            self.threadGetData = None
            self.btnA.setText("Start getData(QThread)")
    
        def on_threadSignalGetData(self, value):
            self.myNumber = value
            self.msgGetData.label.setText(str(self.myNumber))
            if not self.msgGetData.isVisible():        
                self.msgGetData.show() 
        # --END-- getData(QThread) -------------------# 
    
        # ---- processData(QThread) -----------------------------------------------------#    
        def usingProcessData(self):
            if self.threadProcessData is None:
                self.threadProcessData = processData(self.myNumber) 
                self.threadProcessData.threadSignalProcessData.connect(self.on_threadSignalProcessData)
                self.threadProcessData.finished.connect(self.finishedProcessData)
                self.threadProcessData.start()
                self.btnB.setText("Stop processData(QThread)")
            else:
                self.threadProcessData.terminate()         
                self.threadProcessData = None
                self.btnB.setText("Start processData(QThread)")    
    
        def finishedProcessData(self):
            self.threadProcessData = None
            self.btnB.setText("Start processData(QThread)")
    
        def on_threadSignalProcessData(self, value1, value2):
            self.newNumber = value2                                                         
            self.msgProcessData.label.setText(str(value1)+" * 10 = "+str(self.newNumber))   
            if not self.msgProcessData.isVisible():        
                self.msgProcessData.show() 
        # --END-- processData(QThread) -------------------#     
    
    
        # --------------------  closeEvent  --------------------------------------- #  
        def closeEvent(self, event):
            reply = Qt.QMessageBox.question\
            (self, 'Question',
                "QUIT ?",
                 Qt.QMessageBox.Yes,
                 Qt.QMessageBox.No)
            if reply == Qt.QMessageBox.Yes:
    
                # close getData(QThread)
                if self.threadGetData:
                    self.threadGetData.terminate()
                self.msgGetData.close()
    
                # close processData(QThread)
                if self.threadProcessData:
                    self.threadProcessData.terminate()
                self.msgProcessData.close()            
    
                #event.accept()
                super().closeEvent(event)
            else:
                event.ignore()
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        window = Ui()
        sys.exit(app.exec_())
    

    enter image description here