Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyQt4 signals and slots

I am writing my first Python app with PyQt4. I have a MainWindow and a Dialog class, which is a part of MainWindow class:

self.loginDialog = LoginDialog();

I use slots and signals. Here's a connection made in MainWindow:

QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL("aa(str)"), self.login)

And I try to emit signal inside the Dialog class (I'm sure it is emitted):

self.emit(QtCore.SIGNAL("aa"), "jacek")

Unfortunately, slot is not invoked. I tried with no arguments as well, different styles of emitting signal. No errors, no warnings in the code. What might be the problem?

like image 221
Jacek Avatar asked Jan 12 '10 10:01

Jacek


2 Answers

There are some concepts to be clarified

[QT signal & slot] VS [Python signal & slot]

All the predefined signals & slots provided by pyqt are implemented by QT's c++ code. Whenever you want to have a customized signal & slot in Python, it is a python signal & slot. Hence there are four cases to emits a signal to a slot:

  • from a QT signal to a QT slot
  • from a QT signal to a Python slot
  • from a Python signal to a QT slot
  • from a Python signal to a Python slot

The code below shows how to connect for these four different scnarios

    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *

    class Foo(QtCore.QObject):

        def __init__(self, parent=None):
            super(Foo, self).__init__(parent)
            dial = QDial()
            self.spinbox = QSpinbox()

            # --------------------------------------
            # QT signal & QT slot
            # --------------------------------------

            # option 1: more efficient 
            self.connect(self.spinbox, SIGNAL("valueChanged(int)"), 
                dial, SLOT("setValue(int)"))
            # option 2:
            self.connect(self.spinbox, SIGNAL("valueChanged(int)"), 
                dial.setValue)


            # --------------------------------------
            # QT signal & Python slot
            # --------------------------------------

            self.connect(self.spinbox, SIGNAL("valueChanged(int)"), 
                self.myValChanged)


            # --------------------------------------
            # Python signal & Qt slot
            # --------------------------------------

            # connect option 1: more efficient
            self.connect(self, SIGNAL("mysignal"), dial, 
                SLOT("setValue(int)"))

            # connect option 2:
            self.connect(self, SIGNAL("mysignal"), dial.setValue)

            # emit
            param = 100
            self.emit(SIGNAL("mysignal"), param)


            # --------------------------------------
            # Python signal & Python slot
            # --------------------------------------

            # connect
            self.connect(self, SIGNAL("mysignal"), self.myValChanged)

            # emit
            param = 100
            self.emit(SIGNAL("mysignal"), param)


    def myValChanged(self):
        print "New spin val entered {0}".format(self.spinbox.value())

Conclusion is --

Signal signature for Python signal differentiate from that of QT signal in that it doesn't have the parenthesis and can be passed any python data types when you emit it. The Python signal is created when you emit it.

For slot, there are three forms of signatures.

  • s.connect(w, SIGNAL("signalSignature"), functionName)
  • s.connect(w,SIGNAL("signalSignature"), instance.methodName)
  • s.connect(w,SIGNAL("signalSignature"), instance, SLOT("slotSignature"))

Number 1 & 2 are available for Python slot, while number 2 & 3 are available for QT slot. It is clear that besides QT predefined slot, any python callable function/methods is qulified to be a Python slot.

These points are made in Summerfield's article on Signals and Slots.

[Old style qt signal & slot] VS [new style qt singal & slot]

Well, all the description above is based on the old style pyqt signal & slot. As @Idan K suggested there is an alternative new-style to do the things, especially for the Python signal. Refer to here for more.

like image 102
rodney Avatar answered Oct 15 '22 05:10

rodney


You don't use the same signal, when emitting and connecting.

QtCore.SIGNAL("aa(str)") is not the same as QtCore.SIGNAL("aa"). Signals must have the same signature. By the way, if you are defining your own signals, don't define parametres. Just write SIGNAL('aa'), because defining parametres is a thing from C++ and Python version of Qt doesn't need this.

So it should look like this:

QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL("aa"), self.login)

and if you pass any parametres in emit, your login method must accept those parametres. Check, if this helps :-)

like image 12
gruszczy Avatar answered Oct 15 '22 05:10

gruszczy