PyQt threads and signals - how to properly retrieve values

Posted by Cawas on Stack Overflow See other posts from Stack Overflow or by Cawas
Published on 2010-05-18T00:23:29Z Indexed on 2010/05/18 0:30 UTC
Read the original article Hit count: 459

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.

© Stack Overflow or respective owner

Related posts about python

Related posts about pyqt