New-style signal-slot connection mechanism in PyQt

April 24th, 2011 at 6:49 pm

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!

PyQt 4.5 was released almost 2 years ago – it’s time to switch to the new mechanism.

Related posts:

  1. Passing extra arguments to PyQt slots
  2. Creating splash screens in PyQt
  3. Code sample – socket client based on Twisted with PyQt
  4. Sample using QScintilla with PyQt
  5. Tetris implemented in PyQt

10 Responses to “New-style signal-slot connection mechanism in PyQt”

  1. dfNo Gravatar Says:

    You might also consider switching to PySide, which is essentally compatible with PyQt but is LGPL’d and developed by Nokia.

  2. FranklinNo Gravatar Says:

    wow! I’m using PyQt for a while and didn’t knew that!

    But how it works when you have both “clicked()” and “clicked(bool)” versions of the slot, like in the QCheckBox object?

  3. elibenNo Gravatar Says:

    df,

    I’ve mentioned PySide in the blog in the past. Interestingly, it also has a similar “new-style” connection mechanism.

    Franklin,

    This is actually covered in the PyQt documentation. Your slot will fire for both signals. If you want more fine-grained control you should use the @pyqtSlot decorator.

  4. SateeshNo Gravatar Says:

    Also it is possible to use Python decorator syntax to make connection between a signal and slot:

    For example:

    box = QComboBox()
    
    @box.currentIndexChanged.connect
    def handle(index):
        ....
        ....

    (PyQt versiosn 4.7.4)

    The above code snippet connects the currentIndexChanged signal (which is emitted when the current index in the ComboBox is changed) with the method handle.

  5. AlquimistaNo Gravatar Says:

    @Sateesh i didn’t knew that, now the code is more cleaner

  6. DannyNo Gravatar Says:

    Ah, this is good to know. I never knew!

    thanks Eli

  7. codemanNo Gravatar Says:

    nice to learn new things, the code is much easier,

  8. CholavendhanNo Gravatar Says:

    self.ui.comboBox.activated.connect(self.pass_Net_Adap)

    def pass_Net_Adap(self):
    print ” Adap”
    print str(self.ui.comboBox.currentText())

  9. oglopNo Gravatar Says:

    hi eliben, but then how do i emit this signal in a model . setData function ?
    self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index)
    in new style ?

  10. JeffNo Gravatar Says:

    Thank you, thank you thank you! I didn’t know where to start looking for the new connect syntax.

Leave a Reply

To post code with preserved formatting, enclose it in `backticks` (even multiple lines)