[PyKDE] Emitting Python Objects in PyQt4

Phil Thompson phil at riverbankcomputing.co.uk
Sun Feb 19 12:12:24 GMT 2006


Current snapshots now support emitting arbitrary Python objects, ie. objects 
that have no corresponding C++ type.

In PyQt3 a connection between a Python signal and a Python slot (ie. a 
callable) is implemented directly and doesn't involve Qt's signal/slot 
mechanism at all. Therefore no conversion of the signal arguments is required 
and the argument list in the signature passed to PYSIGNAL() is optional and 
ignored. (I tend to specify it in my own code just as additional 
documentation.) To emit something like a Python list is done simply as...

    self.emit(PYSIGNAL("signalIntList(int, List)"), (1, []))

...or...

    self.emit(PYSIGNAL("signalIntList"), (1, []))

In PyQt4 all connections are implemented using Qt's signal/slot mechanism. 
This is to support asynchronous and inter-thread connections for all 
connection types. A consequence is that all Python arguments have to be 
converted to C++ types - including those that SIP doesn't know how to 
convert.

To solve this SIP now recognises "PyObject *" as a special argument type. 
(This is the C type the Python API uses to hold any Python object.) It 
handles it by passing the argument unconverted. The above example would then 
be written in PyQt4 as follows...

    self.emit(SIGNAL("signalIntList(int, PyObject *)"), 1, [])

Note that the int argument is converted to a C++ int for the connection and 
back to a Python object when the Python slot is called. The convertion can be 
prevented by telling SIP to treat it as an arbitrary object just like the 
list, so that the following is slightly quicker...

    self.emit(SIGNAL("signalIntList(PyObject *, PyObject *)"), 1, [])

This all works and is consistent - but rather clumsy. Therefore you can also 
specify a "short-circuit" signal by omitting the argument list and () from 
the signature. This is the equivalent of specifying "PyObject *" for every 
argument. This then gives a usage very similar to that of PyQt3...

    self.emit(SIGNAL("signalIntList"), 1, [])

...which is what you'll end up doing 99% of the time.

Note that you can only connect short-circuit signals to other short-circuit 
signals or Python slots - not to Qt signals or slots.

Disconnecting isn't properly handled yet - I'll add that in the next day or 
so.

Phil




More information about the PyQt mailing list