Venom
Venom

Reputation: 1047

PyQt5 - cannot resolve a dialog's slot

I'm trying to port a small Qt C++ app to Python using PyQt5 but I am having trouble with the most basic stuff right now.
I've used the pyuic utility to transform a .ui file to its corresponding .py file representing the dialog's statically defined UI and exactly two signal/slot pairs (two buttons). The exact error is "'QDialog' object has no attribute 'pushButtonStartClick'" and while I understand what it is describing I don't know how exactly to fix it. I'm not even sure custom slots can be defined in the Ui class. If that is true, it represents a pretty huge limitation. I'm using PyQt 5.4 and Python 2.7 on a Windows machine.

Additional info - simple tutorial I've been reading and trying to emulate.

Thank you in advance.

Generated .py file containing the UI class (part of it, source .ui file is here):

class Ui_NewGameDialog(object):
    def setupUi(self, NewGameDialog):
        NewGameDialog.setObjectName("NewGameDialog")
        NewGameDialog.setWindowModality(QtCore.Qt.ApplicationModal)
        NewGameDialog.resize(265, 200)
        #
        # ...
        #
        self.retranslateUi(NewGameDialog)
        # part where it breaks apart
        self.pushButtonStart.clicked.connect(NewGameDialog.pushButtonStartClick)
        self.pushButtonCancel.clicked.connect(NewGameDialog.pushButtonCancelClick)
        QtCore.QMetaObject.connectSlotsByName(NewGameDialog)

Class that inherits it:

class NewGameDialog(Ui_NewGameDialog):
    def __init__(self, dialog):
        Ui_NewGameDialog.__init__(self)
        self.setupUi(dialog)
        dialog.setFixedSize(dialog.size())
        dialog.setWindowFlags(
                dialog.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint
        )

    @pyqtSlot(name="pushButtonStartClick")
    def pushButtonStartClick(self):
        pass

    @pyqtSlot(name="pushButtonCancelClick")
    def pushButtonCancelClick(self):
        pass

Initialization:

if __name__ == "__main__":
    app = QApplication(sys.argv)

    dialog = QtWidgets.QDialog()
    ui = NewGameDialog(dialog)
    dialog.show()

    sys.exit(app.exec_())

Upvotes: 1

Views: 326

Answers (2)

J.J. Hakala
J.J. Hakala

Reputation: 6214

I think setupUi method was getting a wrong kind of object, since QDialog doesn't have those pushButtonStartClick and pushButtonCancelClick.

class NewGameDialog(QtGui.QDialog, Ui_NewGameDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        Ui_NewGameDialog.__init__(self)
        self.setupUi(self)
        self.setFixedSize(self.size())
        self.setWindowFlags(
            self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint
        )

    @pyqtSlot(name="pushButtonStartClick")
    def pushButtonStartClick(self):
        pass

    @pyqtSlot(name="pushButtonCancelClick")
    def pushButtonCancelClick(self):
        pass

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    dialog = NewGameDialog()
    dialog.show()

    sys.exit(app.exec_())

Without multiple inheritance:

class NewGameDialog(QtGui.QDialog):
    def __init__(self):
        super(NewGameDialog, self).__init__()
        self.ui = Ui_NewGameDialog()
        self.ui.setupUi(self)
...

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    dialog = NewGameDialog()

Upvotes: 1

three_pineapples
three_pineapples

Reputation: 11869

The answer by @JJHakala (that uses multiple inheritance) is option 3 in the PyQt documentation. Option 2 also suits your situation (this is a slightly more elegant version of the "without multiple inheritance" option presented in J. J. Hakala's edit, based on the example in the PyQt docs):

class NewGameDialog(QtWidgets.QDialog):
    def __init__(self):
        QtWidgets.QDialog.__init__(self)
        self.ui = Ui_NewGameDialog()
        self.ui.setupUi(self)
        self.setFixedSize(self.size())
        self.setWindowFlags(
                self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint
        )

    @pyqtSlot(name="pushButtonStartClick")
    def pushButtonStartClick(self):
        pass

    @pyqtSlot(name="pushButtonCancelClick")
    def pushButtonCancelClick(self):
        pass

if __name__ == "__main__":
    app = QApplication(sys.argv)

    dialog = NewGameDialog()
    dialog.show()

    sys.exit(app.exec_())

Upvotes: 1

Related Questions