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()