pythonpyqtsignals-slotsqthread

Python sending signals between two QThreads


I am having trouble sending a signal from one qthread to another. A similar extract of code I am using is below:

class auth(QtCore.QThread):
    authenticate = pyqtSignal()
    serverDown = pyqtSignal()
    accntonline = pyqtSignal()

    def __init__(self, parent=None):
        super(auth, self).__init__(parent)
    def run(self):
        self.authenticate.emit()

class Threadclass(QtCore.QThread):
    authenticator = "n"
    def __init__(self, parent=None):

        super(Threadclass, self).__init__(parent)
        #setting first values avoiding errors

        self.a = auth(self)

        self.a.authenticate.connect(self.setauthentication)

    #All small functions setting values from box.

    def setauthentication(self):
        print("awdawdawda")
        self.authenticator = "y"

When I run the thread auth the variable self.authenticator does not change. it stays at "n". all help appreciated


Solution

  • If you override the run method of a QThread, it will not start its own event-loop unless you explicitly call its exec method. The event-loop is required for processing cross-thread signals. Because of this, it's usually better to create a worker object and move it to the thread, rather than overriding run.

    Here is a demo script that shows how to use worker objects with threads:

    import sys
    from PyQt5 import QtWidgets, QtCore
    
    class AuthWorker(QtCore.QObject):
        authenticate = QtCore.pyqtSignal()
    
        def __init__(self):
            super(AuthWorker, self).__init__()
    
        def run(self):
            QtCore.QThread.sleep(0.5)
            self.authenticate.emit()
    
    class Worker(QtCore.QObject):
        finished = QtCore.pyqtSignal(str)
        authenticator = "n"
    
        def __init__(self, parent=None):
            super(Worker, self).__init__(parent)
            self.auth = AuthWorker()
            self.auth_thread = QtCore.QThread()
            self.auth.moveToThread(self.auth_thread)
            self.auth.authenticate.connect(self.setauthentication)
            self.auth_thread.started.connect(self.auth.run)
    
        def setauthentication(self):
            self.authenticator = "y"
    
        def run(self):
            self.auth_thread.start()
            QtCore.QThread.sleep(1)
            self.finished.emit('auth: %s' % self.authenticator)
    
    class Window(QtWidgets.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.button = QtWidgets.QPushButton('Test', self)
            self.button.clicked.connect(self.handleButton)
            self.edit = QtWidgets.QLineEdit(self)
            self.edit.setReadOnly(True)
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(self.edit)
            layout.addWidget(self.button)
            self.thread = QtCore.QThread()
            self.worker = Worker()
            self.worker.moveToThread(self.thread)
            self.worker.finished.connect(self.handleFinished)
            self.thread.started.connect(self.worker.run)
    
        def handleFinished(self, text):
            self.thread.quit()
            self.edit.setText(text)
    
        def handleButton(self):
            if not self.thread.isRunning():
                self.edit.clear()
                self.thread.start()
    
    if __name__ == '__main__':
    
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.setGeometry(600, 100, 200, 100)
        window.show()
        sys.exit(app.exec_())