Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyQt: Wrapping Dialog from QDesigner and Connect pushbutton

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))
like image 228
BerndGit Avatar asked Jan 06 '15 17:01

BerndGit


2 Answers

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.

like image 126
ekhumoro Avatar answered Sep 24 '22 12:09

ekhumoro


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.

like image 26
ProgrammingIsAwsome Avatar answered Sep 24 '22 12:09

ProgrammingIsAwsome