I'm starting to learn Python and PyQt. Currently I am fighting with a very basic problem about connecting signals and Slots, with Dialog forms generated form QDesigner. I want to connect a pushbutton from a QDialog. The code does not generate an error. The Dialog is show, as expected. But with clicking on the pushbuttons nothing happens.
Alternatively I have tried included the code form Ui_Dialog
directly in my target class Testdialog
. Then the connection was working. It seems like i made an error in inheriting the properties from Ui_Dialog
to Testdialog
and/or in the way I want to execute the Dialog.
My main program looks like:
from __future__ import unicode_literals
import sys
from PyQt4 import *
from PyQt4 import QtGui
from PyQt4.QtCore import SIGNAL, QObject
import UI_Test
class Testdialog(QtGui.QDialog, UI_Test.Ui_Dialog):
def __init__(self,parent=None):
super(Testdialog, self).__init__(parent)
self.setupUi(self)
print("Connect buttons") # gives the expected output
self.connect(self.pushButton_Ok, SIGNAL("clicked()"), self.clickedOk)
self.connect(self.pushButton_Cancel, SIGNAL("clicked()"), self.clickedCancel)
# Alternativly I have tríed the following without improvement:
# self.pushButton_Ok.clicked.connect(self.clickedOk)
# QObject.connect(self.pushButton_Cancel, SIGNAL("clicked()"), self.clickedCancel)
def clickedCancel(self):
print ("Cancel") # Question: Why is nothing happening here?
def clickedOk(self):
print ("Ok") # Question: Why is nothing happening here?
if True:
qApp = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
u = Testdialog()
u.setupUi(Dialog)
Dialog.exec_()
sys.exit(qApp.exec_())
When I click on the bushbuttons nothing happens. It seems like the connection is not working.
What did i do wrong? How tho fix it? What else should be improved?
The form UI_Test.py
is nothing special, since it is automatically generated with QtDesigner and pyuic. So basically it should be ok (although I don't understand every detail about the code).
In order to provide to a running example, here is the code:
# File: UI_Test.py
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(271, 70)
self.pushButton_Ok = QtGui.QPushButton(Dialog)
self.pushButton_Ok.setGeometry(QtCore.QRect(20, 20, 93, 28))
self.pushButton_Ok.setObjectName(_fromUtf8("pushButton_Ok"))
self.pushButton_Cancel = QtGui.QPushButton(Dialog)
self.pushButton_Cancel.setGeometry(QtCore.QRect(130, 20, 93, 28))
self.pushButton_Cancel.setObjectName(_fromUtf8("pushButton_Cancel"))
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
Dialog.setWindowTitle(_translate("Dialog", "Dialog", None))
self.pushButton_Ok.setText(_translate("Dialog", "OK", None))
self.pushButton_Cancel.setText(_translate("Dialog", "Cancel", None))
The problem in the original code is in this section:
if True:
qApp = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
u = Testdialog()
u.setupUi(Dialog)
Dialog.exec_()
sys.exit(qApp.exec_())
What you want instead is something like this:
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
u = Testdialog()
u.show()
sys.exit(app.exec_())
The reason why the original code doesn't work, is because the signal connections are only made in the __init__
of Testdialog
. The instance of Testdialog
you create has all the ui added to it, and all the signals are connected up correctly, but you never actually show it! Instead, you show the other dialog you created (i.e. Dialog
), which gets a new copy of the same ui added to it (via setupUi
) - but without the signal connections.
Hey so here is my answer. I just made the same example without the QtDesigner (just copy paste and runt it):
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.Qt import pyqtSlot
class MyDialog(QtGui.QDialog):
def __init__(self):
super(MyDialog, self).__init__()
self.resize(271, 70)
self.pushButton_Ok = QtGui.QPushButton(self)
self.pushButton_Ok.setGeometry(QtCore.QRect(20, 20, 93, 28))
self.pushButton_Ok.setText("Ok")
self.pushButton_Cancel = QtGui.QPushButton(self)
self.pushButton_Cancel.setGeometry(QtCore.QRect(130, 20, 93, 28))
self.pushButton_Cancel.setText("Cancel")
# HERE the slots are connected
self.pushButton_Ok.clicked.connect(self.clickedOk) # new style signal/slot
self.pushButton_Cancel.clicked.connect(self.clickedCancel) # new style signal/slot
@pyqtSlot()
def clickedCancel(self):
print ("Cancel pressed")
@pyqtSlot()
def clickedOk(self):
print ("Ok pressed")
qApp = QtGui.QApplication(sys.argv)
dial = MyDialog()
dial.show()
sys.exit(qApp.exec_())
I hope you see now what I meant with don't use the QtDesigner. Because like this example it's much more clear and less code and you understand the better what's going on in the background. I hope my answer helped you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With