简体   繁体   中英

PySide Signals not being sent to Slot, from QThread object

I'm working with a multi-threading application, where a worker thread gets created, that emits a signal. After creating the thread, I connect the signal with an object slot, that will perform some action.

The problem, is the object slot, is not called, can someone help to figure out what's wrong with this code ?

import time
from PySide import QtCore
from PySide.QtCore import Slot, Signal


class Worker1(QtCore.QThread):

    task_done_signal = Signal(int)

    def __init__(self):
        super(Worker1, self).__init__()
        self._run = False

    def run(self):
        self._loop()

    def _loop(self):
        count = 0
        while self._run:
            print("running")
            count += 1
            self.task_done_signal.emit(count)

    def start(self):
        self._run = True
        super(Worker1, self).start()

    def stop(self):
        self._run = False


class Worker1Listener(QtCore.QObject):
    def __init__(self):
        super(Worker1Listener, self).__init__()

    @Slot()
    def print_task(self, val):
        print("listener: {}".format(val))


def test_signals_and_threads():

    # create the thread
    worker = Worker1()

    # create the listener
    listener = Worker1Listener()

    # connect the thread signal with the slot
    worker.task_done_signal.connect(listener.print_task)

    worker.start()

    time.sleep(5)

    worker.stop()

    time.sleep(5)


if __name__ == '__main__':
    test_signals_and_threads()

Your code has several errors:

  • You must have an event loop so that Qt handles communications between the various objects of the application, in your case you must use QCoreApplication .

  • The decorator Slot must have as parameter the type of data of the arguments of the function, in your case: Slot(int)

  • You should not use time.sleep since it is blocking and does not let the event loop do its work, a possible solution is to use QEventLoop next to a QTimer .

  • It is always advisable to give a short time for communications to be given, for this we use QThread.msleep .

  • When you connect between signals that are in different threads, the correct option is to use the Qt.QueuedConnection option.


import sys

from PySide import QtCore

class Worker1(QtCore.QThread):
    task_done_signal = QtCore.Signal(int)

    def __init__(self):
        super(Worker1, self).__init__()
        self._run = False

    def run(self):
        self._loop()

    def _loop(self):
        count = 0
        while self._run:
            print("running")
            count += 1
            self.task_done_signal.emit(count)
            QtCore.QThread.msleep(1)

    def start(self):
        self._run = True
        super(Worker1, self).start()

    def stop(self):
        self._run = False


class Worker1Listener(QtCore.QObject):
    @QtCore.Slot(int)
    def print_task(self, val):
        print("listener: {}".format(val))

def test_signals_and_threads():
    app = QtCore.QCoreApplication(sys.argv)
    # create the thread
    worker = Worker1()
    # create the listener
    listener = Worker1Listener()

    # connect the thread signal with the slot
    worker.task_done_signal.connect(listener.print_task, QtCore.Qt.QueuedConnection)

    worker.start()

    loop = QtCore.QEventLoop()
    QtCore.QTimer.singleShot(5000, loop.quit)
    loop.exec_()

    worker.stop()

    loop = QtCore.QEventLoop()
    QtCore.QTimer.singleShot(5000, loop.quit)
    loop.exec_()

    #sys.exit(app.exec_())

if __name__ == '__main__':
    test_signals_and_threads()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM