PyQt4 signals and slots
Solution 1
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 :-)
Solution 2
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.
Solution 3
What @bialix suggested should have worked, but try an alternative way of connecting:
class Foo(QtCore.QObject):
mysignal = QtCore.pyqtSignal(str, name='mysignal')
def connect_to_signal(self):
# you can use this syntax instead of the 'old' one
self.mysignal.connect(self.myslot)
# but this will also work
self.connect(self, QtCore.SIGNAL('mysignal(QString)'), self.myslot)
self.mysignal.emit("hello")
def myslot(self, param):
print "received %s" % param
For a more detailed explanation of how signals/slots work in PyQt I'd suggest going through it's documentation, specifically this section.
Solution 4
I checked your code and it looks like the problem is in the way how you're connecting your signal
you emit the signal in Ui_Dialog class
self.emit(QtCore.SIGNAL("aa()"))
you connect to the signal in Ui_MainWindow's setupUi method by calling
QtCore.QObject.connect(self.loginDialog.ui, QtCore.SIGNAL("aa()"), self.login)
notice first parameter is changed to self.loginDialog.ui; your original connect call was using self.loginDialog which is of the LoginDialog type, whereas signal is emitted by the Ui_Dialog class which is ui property of the LoginDialog. After this change login method of the Ui_MainWindow got called
hope this helps, regards
Solution 5
As noted by gruszczy you have to use the same QtCore.SIGNAL('xxx') to connect signal and to emit it. Also I think you should use Qt types in the arguments list of signal function. E.g.:
QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL("aa(QString&)"), self.login)
And then emit with:
self.emit(QtCore.SIGNAL("aa(QString&)"), "jacek")
Sometimes it makes sense to define signal only once as global variable and use it elsewhere:
MYSIGNAL = QtCore.SIGNAL("aa(QString&)")
...
QtCore.QObject.connect(self.loginDialog, MYSIGNAL, self.login)
...
self.emit(MYSIGNAL, "jacek")
Jacek
Updated on July 12, 2022Comments
-
Jacek almost 2 years
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?
-
bialix over 14 yearsSLOT is not necessary in PyQt4. Just callable is enough.
-
Jacek over 14 yearsError: QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL('aa()'), self, QtCore.SIGNAL('login()')) RuntimeError: underlying C/C++ object has been deleted Thanks anyway ;)
-
Jacek over 14 yearsThat was my mistake in pasting the code. I cut it to be more readable. I didin't do it in the real code. Thanks for a hint ;)
-
Jacek over 14 yearsUnfortunataly, it does not work. QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL('aa'), QtCore.SIGNAL('login')) TypeError: QObject.connect(): arguments did not match any overloaded call: overload 1: argument 3 has unexpected type 'str' overload 2: argument 3 has unexpected type 'str' overload 3: argument 2 has unexpected type 'str' Thanks anyway :)
-
Jacek over 14 yearsStill, nothing happens. I also tried to emit with no arguments, I failed again. Thanks for a hint.
-
gruszczy over 14 yearsCould you post some more of your code? Maybe the whole snippet. Then I can try to help you.
-
bialix over 14 yearsWhich version of PyQt you're using?
-
bialix over 14 yearsShould be QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL('aa()'), self, QtCore.SLOT('login()'))
-
Jacek over 14 yearsI would be grateful. The code is avaliable here: github.com/jbajor/Pwitter . Code I have problems with: ptwitt_win.py, line 83-98, ptwitter_login.py, line 54-58.
-
Jacek over 14 yearsYou're right Bialix. Unfortunately I still get: QtCore.QObject.connect(self.loginDialog, QtCore.SIGNAL('aa()'), self, QtCore.SLOT('login()')) RuntimeError: underlying C/C++ object has been deleted
-
Jacek over 14 yearsPyQt4 263682 (returned by QtCore.PYQT_VERSION)
-
gruszczy over 14 yearsI assume, you are sure, that code enters login method in ptwitter_login.py. Try connecting this way: self.connect(self.loginDialog, QtCore.SIGNAL('aa'), self.login) Remember to remove brackets after aa. This kind of connecting always worked for me.
-
bialix over 14 yearsQtCore.PYQT_VERSION_STR will show you human-readable string. But it seems you're using 4.6.2. I dunno why it does not work for you.
-
Jacek over 14 yearsDoes not work. Thanks for input though. I would be grateful for any new ideas.
-
Idan K over 14 yearsTry creating a separate script with the code I've written and call connect_to_signal on a Foo object, do you see any output?
-
gruszczy over 14 yearsWell, I have no further idea then. You must have some error somewhere deeper.
-
Eugene Sajine over 11 yearsIMHO, awesome explanation! One of the best I was able to find so far!
-
mikuszefski about 11 yearsMust agree, one of the best! Thanks!