April 24, 2011 at 18:49 Tags Python , Qt

In most of the PyQt code samples you find online and in books (including, I confess, my examples and blog posts) the "old-style" signal-slot connection mechanism is used. For example, here's a basic push-button window:

from PyQt4.QtCore import * from PyQt4.QtGui import * class MyForm (QMainWindow): def __init__ ( self , parent= None ): super (MyForm, self ).__init__(parent) the_button = QPushButton( 'Hello' ) self .connect(the_button, SIGNAL( 'clicked()' ), self .on_hello) self .setCentralWidget(the_button) def on_hello ( self ): print ( 'hello!!' ) if __name__ == "__main__" : import sys app = QApplication(sys.argv) form = MyForm() form.show() app.exec_()

The relevant code is:

self .connect(the_button, SIGNAL( 'clicked()' ), self .on_hello)

Apart from being verbose and un-Pythonic, this syntax has a serious problem. You must type in the C++ signature of the signal exactly. Otherwise, the signal just won't fire, without an exception or any warning. This is a very common mistake. If you think that clicked() is a simple enough signature to write, how about these ones (taken from real code):

SIGNAL( "currentRowChanged(QModelIndex,QModelIndex)" ) SIGNAL( 'marginClicked(int, int, Qt::KeyboardModifiers)' )

The "new-style" signal-slot connection mechanism is much better. Here's how the button click connection is done:

the_button.clicked.connect( self .on_hello)

This mechanism is supported by PyQt since version 4.5, and provides a safer and much more convenient way to connect signals and slots. Each signal is now an attribute that gets automatically bound once you access it. It has a connect method that simply accepts the slot as a Python callable. No more C++ signatures, yay!