[PyQt] Proposal for New-style Signals
Phil Thompson
phil at riverbankcomputing.com
Mon Jan 21 15:20:16 GMT 2008
This reflects my current thinking on introducing new, more convenient ways of
using signals in PyQt. The aims are twofold: to make the use of signals less
error prone and less verbose.
Any changes must preserve backwards compatibility and must provide a general
solution (not just for Qt but also 3rd party libraries that might not have
the same level of thought put into their APIs).
A key question is how to specify signatures, ie. using strings (as now), or
using a sequence of Python type objects, or using some naming convention for
methods. I intend to retain the use of strings because:
- they are guaranteed to be flexible enough for future needs
- Python types aren't specific enough to cover all C++ types
- to be consistent with __pyqtSignals__, pyqtProperty and pyqtSignature.
I plan to make changes in two stages.
Stage 1
The use of SIGNAL() will become optional for Qt signals and short-circuit
signals. SIGNAL() must still be used for Python signals (but Python signals
should be considered deprecated in favour of short-circuit signals). Note
that a signal defined dynamically using __pyqtSignals__ is considered to be a
Qt signal.
Signals are passed to QObject's [dis]connect() and emit() methods. Currently,
If the signal is invalid then no indication is provided to that effect. If a
simple string is used instead of SIGNAL() then an invalid Qt signal will
cause a Python exception to be raised. As now, an "invalid" short-circuit
signal will not cause an exception to be raised.
For example:
QObject.connect(btn, 'clicked()', self.on_clicked)
QObject.connect(foo, 'zapped', on_zapped)
btn.emit('clicked()')
foo.emit('zapped', arg1, arg2)
Question: It would be possible to allow (but not require) short-circuit
signals to be predefined using __pyqtSignals__. [dis]connect() and emit()
could then check the name (but not any arguments) of the signal. A check
would only fail if at least one short-circuit signal had been defined (to
preserve backwards compatibility). Is this worthwhile? (My feeling is no.)
Stage 2
The Qt signals with a particular name will be represented by a new signal
object stored as a class attribute. Individual signals (ie. with a
particular signature) will be accessed as an index using a string containing
a comma separated list of argument types as the key.
Each individual signal will have [dis]connect() and emit() methods.
For example:
btn.clicked[''].connect(self.on_clicked)
btn.clicked['bool'].connect(self.on_clicked_checked)
btn.toggled['bool'].emit(True)
In addition, for signal overloads with no arguments (ie. with '' as the signal
key) the index can be omitted as follows:
btn.clicked.connect(self.on_clicked)
Note that for a signal with at least one argument, but without an overload
that has no arguments, this "short form" is invalid. This is to allow for
the addition of a no-argument overload some time in the future.
Question: An alternative approach would be to define a "default" signal (in
the .sip files) which would identify the overload to be used with the "short
form". As most Qt signals aren't overloaded this would mean that the type
string would not have to be specified in the majority of cases. Is this
worthwhile? (My feeling is yes.)
The signal names (but not the types) will be included in the API file for code
completion support.
Thanks to those who have been throwing their ideas around. Comments welcome.
Phil
More information about the PyQt
mailing list