PyQt threads and signals - how to properly retrieve values
- by Cawas
Using Python 2.5 and PyQt, I couldn't find any question this specific in Python, so sorry if I'm repeating the other Qt referenced questions below, but I couldn't easily understand that C code.
I've got two classes, a GUI and a thread, and I'm trying to get return values from the thread. I've used the link in here as base to write my code, which is working just fine. To sum it up and illustrate the question in code here (I don't think this code will run on itself):
class MainWindow (QtGui.QWidget):
# this is just a reference and not really relevant to the question
def __init__ (self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.thread = Worker() # this does not begin a thread - look at "Worker.run" for mor details
self.connect(self.thread, QtCore.SIGNAL('finished()'), self.unfreezeUi)
self.connect(self.thread, QtCore.SIGNAL('terminated()'), self.unfreezeUi)
self.connect(self.buttonDaemon, QtCore.SIGNAL('clicked()'), self.pressDaemon)
# the problem begins below: I'm not using signals, or queue, or whatever, while I believe I should
def pressDaemon (self):
self.buttonDaemon.setEnabled(False)
if self.thread.isDaemonRunning():
self.thread.setDaemonStopSignal(True)
self.buttonDaemon.setText('Daemon - converts every %s sec'% args['daemonInterval'])
else:
self.buttonConvert.setEnabled(False)
self.thread.startDaemon()
self.buttonDaemon.setText('Stop Daemon')
self.buttonDaemon.setEnabled(True)
# this whole class is just another reference
class Worker (QtCore.QThread):
daemonIsRunning = False
daemonStopSignal = False
daemonCurrentDelay = 0
def isDaemonRunning (self): return self.daemonIsRunning
def setDaemonStopSignal (self, bool): self.daemonStopSignal = bool
def __init__ (self, parent = None):
QtCore.QThread.__init__(self, parent)
self.exiting = False
self.thread_to_run = None # which def will be running
def __del__ (self):
self.exiting = True
self.thread_to_run = None
self.wait()
def run (self):
if self.thread_to_run != None:
self.thread_to_run(mode='continue')
def startDaemon (self, mode = 'run'):
if mode == 'run':
self.thread_to_run = self.startDaemon # I'd love to be able to just pass this as an argument on start() below
return self.start() # this will begin the thread
# this is where the thread actually begins
self.daemonIsRunning = True
self.daemonStopSignal = False
sleepStep = 0.1 # don't know how to interrupt while sleeping - so the less sleepStep, the faster StopSignal will work
# begins the daemon in an "infinite" loop
while self.daemonStopSignal == False and not self.exiting:
# here, do any kind of daemon service
delay = 0
while self.daemonStopSignal == False and not self.exiting and delay < args['daemonInterval']:
time.sleep(sleepStep) # delay is actually set by while, but this holds for N second
delay += sleepStep
# daemon stopped, reseting everything
self.daemonIsRunning = False
self.emit(QtCore.SIGNAL('terminated'))
Tho it's quite big, I hope this is pretty clear. The main point is on def pressDaemon. Specifically all 3 self.thread calls. The last one, self.thread.startDaemon() is just fine, and exactly as the example. I doubt that represents any issue.
The problem is being able to set the Daemon Stop Signal and retrieve the value if it's running. I'm not sure that it's possible to set a stop signal on QtCore.QtThread, because I've tried doing the same way and it didn't work. But I'm pretty sure it's not possible to retrieve a return result from the emit.
So, there it is. I'm using direct calls to the thread class, and I'm almost positive that's not a good design and will probably fail when running under stress. I read about that queue, but I'm not sure it's the proper solution here, or if I should be using Qt at all, since this is Python. And just maybe there's nothing wrong with the way I'm doing.