bankai-code
bankai-code

Reputation: 23

Python PyQt4 signal not firing connected method

I decided to use signals to indicate the completion of a thread. I wired the signal to code that restarts the process if more work still exists. Alas, the code connected to the signal never fires. This makes me sad.

I need to know why the method 'Tester' in the code block below doesn't fire.

I'm new to python so when I started writing this I researched signals and modelled the code after a solution that tgray posted here and apparently I missed something important, but I seriously just can't see what it is.

Here is a massively simplified version of my code:

from PyQt4.QtCore import *
import time

class Worker(QThread):
    __pyqtSignals__ = ( "a", 
                        "b" )
    def __init__(self):
        QThread.__init__(self, None)


    def run(self):
        print "'Worker.run' starts"
        self.emit(SIGNAL("a"))
        print "'Worker.run' ends"


class Main:
    def Do(self):
        print "'Do' starts"
        self.Launch()
        time.sleep(2)
        print "'Do' ends"


    def Launch(self):
        print "'Launch' starts"
        self.worker = Worker()
        QObject.connect(self.worker, SIGNAL("a"), self.Tester)
        self.worker.daemon = True
        self.worker.start()
        print "'Launch' ends"


    def Tester(self):
        print "Tester Fired!!"

m=Main()

Running:

>>> m.Do()

Yields:

'Do' starts
'Launch' starts
'Launch' ends
'Do' ends
'Worker.run' starts
'Worker.run' ends

But not the expected:

Tester Fired!!

What did I miss? Also, why do the prints in "Worker.run" appear after everything else even with the sleep(2)?

Upvotes: 2

Views: 1785

Answers (1)

mguijarr
mguijarr

Reputation: 7900

If you want to see your callback being called, you have to change the way you connect your QThread signal to your slot:

 QtCore.QObject.connect(self.worker,
                        Qt.SIGNAL("a"),
                        self.Tester,
                        Qt.Qt.DirectConnection) #this is added

Explanation: Qt signals/slots are thread safe since Qt 4. Documentation says the normal behaviour when connecting a signal to a slot is 'AutoConnection', which means it is direct (callback is fired immediately after emit) if both signal and slot are in the same thread, whereas it is queued if the signal is emitted from another thread (your case).

Then, something has to process this queue: normally, this is done by the Qt loop while your application is running.

The fact that a signal is "queued" means control is transferred to the Qt loop, to make sure the callback is called in the main thread even if the signal comes from another thread.

In your question's code, there is no event loop at all - so the only way of getting your slots called from another thread is to change the way signals are dispatched. Don't use that in your code, though, since in a normal application you have the Qt loop running, it would have been dispatched properly (and safely from threading issues).

Upvotes: 4

Related Questions