0

I am experience with Qt4, but now try to get into the programming of Qt with python.

It works mainly but now I come across a basic python program I did not figure out:

TypeError: setupSignalSlots() takes 1 positional argument but 2 were given

from PyQt4 import QtGui, uic
from PyQt4 import QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        uic.loadUi('MainWindow.ui', self)
        self.show()

        self.setupSignalSlots(self)

    def setupSignalSlots(self):
        self.ui.actionQuit.clicked.connect(OnQuitMainWindow)

    @QtCore.pyqtSlot()
    def OnQuitMainWindow():
        print('quit')
        QApplication.quit()

Besides that problem I wonder if the signal slot code is correct.

Matthias Pospiech
  • 3,130
  • 18
  • 55
  • 76

2 Answers2

3

There are several things wrong with the code you posted.

Firstly, the OnQuitMainWindow slot needs a self argument. However, you do not need to pass this argument explicitly as python will do it automatically. Secondly, when you connect to the slot, you need to access it via self. Finally, quit is not a static method of QApplication, so you need to call it via an instance (e.g. qApp.quit()).

(And one other nit-pick: in python (and Qt, for that matter), it goes against convention to start attribute names with a capital letter).

After making these corrections, your code should look like this:

from PyQt4 import QtGui, uic
from PyQt4 import QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        uic.loadUi('MainWindow.ui', self)
        self.show()

        self.setupSignalSlots()

    def setupSignalSlots(self):
        self.actionQuit.triggered.connect(self.onQuitMainWindow)

    @QtCore.pyqtSlot()
    def onQuitMainWindow(self):
        print('quit')
        QtGui.qApp.quit()

UPDATE:

And one more thing I missed: the way you're using uic.loadUi means that the objects added in Qt Designer will end up as direct attributes of the instance of MainWindow. So it should be self.actionQuit, rather than self.ui.actionQuit. Also, since it appears that this object is a QAction, the signal should be triggered, rather than clicked.

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Ok, I need to read more about pyhtons way of classes. The code here however fails because of `AttributeError: 'MainWindow' object has no attribute 'ui'` – Matthias Pospiech Feb 10 '14 at 05:47
  • @MatthiasPospiech. Apologies - I missed that one. I've updated my answer accordingly. – ekhumoro Feb 10 '14 at 06:49
  • How would the code look like such that the ui is saved in `self.ui`? – Matthias Pospiech Feb 10 '14 at 18:36
  • @MatthiasPospiech. Strictly speaking, you would have `MainWindow(object)`, get rid of the `super` call, and then do `self.ui = uic.loadUi('MainWindow.ui')`. This would mean _all_ methods of the main window and its attributes would need to be prepended with `self.ui` (for example, `self.ui.show()`, `self.ui.actionQuit`, etc). However, I have also seen people just do `self.ui = uic.loadUi('MainWindow.ui', self)` without the other changes - but I don't really see the point of this, since everything would then be accessible via both `self` _and_ `self.ui`. – ekhumoro Feb 10 '14 at 19:09
  • Ok, I understand it so far. Nevertheless I wonder why most tutorials talk only about using `pyuic4` to generate a py file from the ui. And the whole doc page `http://pyqt.sourceforge.net/Docs/PyQt4/designer.html` does not provide any example using `loadUi`. In Qt/C++ loading of the generated ui code file is a must. With python this seems not to be necessary. But most examples dont compare the approaches. – Matthias Pospiech Feb 11 '14 at 21:37
  • @MatthiasPospiech. Personally, I much prefer the `pyuic` approach. It is more efficient than `loadUi` (at runtime), but in any case, I just like to have the python module to hand. It can be particularly helpful to review the code generated by `pyuic` when first learning PyQt. (PS: I did a simple comparison of the two approaches in [this answer](http://stackoverflow.com/a/21540861/984421)). – ekhumoro Feb 11 '14 at 22:03
1

You don't need to pass self to a method of a class; it is automatically done for you. Just do self.setupSignalSlots().

SethMMorton
  • 45,752
  • 12
  • 65
  • 86