Passing python vars in PyQt using SIGNAL/SLOT...


So in QT programming signals and slots are at the heart of a well formed application. In Python (using PyQt) it is not exactly obvious how to start developing your own signals and slots. Hopefully this will help...

First, when signals have no arguments things are pretty simple. Take this example:

QObject.connect(self.timer, SIGNAL("timeout()"), self.processStatus)

As you can see, in PyQt you pass string representations of function prototypes in when setting up the connection between a signal and slot. In this case you can just define a simple python function to hook this baby up and the timer will send out the signal when the timeout occurs:

def processStatus(self):
# Do something useful here...

Now what if you are hooking up to a SIGNAL that has arguments from a core C++ based library, either from QT or from QGIS? Still pretty simple:

QObject.connect(self.view, SIGNAL("customContextMenuRequested(const QPoint &)"), self.processCustomMenu)

Note that the string in the SIGNAL definition must match exactly with the signature of the function... a missed space will send you on a wild debugging ride. From here we can just write a simple processCustomMenu function and expect to receive the point from QT as an argument.

def processCustomMenu(self, position):
# Do something useful with the position...

OK... pretty straight forward so far. Now were it gets slightly tricky is if you are defining your own signals and slots and not interacting with QT or QGIS at all. In this case you can follow the simple scenario for signals with no arguments, but if you are defining your own signal that has arguments you have to employ the following trick:

QObject.connect(self.testThread, SIGNAL("testFinished(PyQt_PyObject)"), self.testFinishedFromThread)

As you can see you have to insert a special PyQt_PyObject in the function prototype. This allows you to pass any arbitrary python object in the signal. On the receiving end you can expect to get your argument.

def testFinishedFromThread(self,success):
print "Model Finished with success = ", success

Finally, to send the signal you can just give the same signature followed by the arguments... any python structure can be passed.

self.emit(SIGNAL("testFinished(PyQt_PyObject)"),success)

You can read more about the signal slot support in PyQt at THIS LINK.

Happy PyQt programming with QGIS!

Hi, this is more a question

Hi,

this is more a question than a comment, perhaps you may help me:

I'm trying to use the function snapPoint of the class QgsVectorLayer. Its signature is: QgsVectorLayer::snapPoint(QgsPoint& point, double tolerance). My Question: Whht does the "QgsPoint&" exactly mean? How may I use the function correctly? By now, I read the "&" as a sort of pointer, although i thought python doesn't have this concept...

with confused greets, carl

Short-circuit Signals

It is very rare that you ever need to use PyQt_PyObject, you should use short-circuit signals instead. For example:

QObject.connect(self.testThread, SIGNAL("testFinished"), self.testFinishedFromThread)

self.emit(SIGNAL("testFinished"), success)

Phil

pass arguments to a clicked() signal

Hi,
I would like to pass arguments to a slot invoked by a clicked() signal of a QPushButton? I haven't found any suitable solution yet. Is there a simple/pythonic way to achieve that?

Cheers Jonas