Search code examples
pythonpyqt5decoupling

Python: decoupling code from PyQt5 UI Code


I'm doing my first steps with PyQt5. I created a simple dialog "form_main" with only 1 menu: "File|Quit":

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction
from PyQt5.QtGui import QIcon

class GUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('MyApp')
        self.resize(400, 300)
        self.statusBar().showMessage('Welcome')
        self.add_menus()

    def add_menus(self):
        menubar = self.menuBar()
        file_menu = menubar.addMenu('&File')

        exit_action = QAction('&Quit', self)
        file_menu.addAction(exit_action) 

Now I want to access this code from another class. In that class I want to define a function that's called when I click on "File|Quit". In a second file I wrote:

from frm_main import GUI
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication

def exit_action():
    self.close

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = GUI()
    # ui.exit_action.triggered.connect(exit_action)
    ui.show()
    sys.exit(app.exec_())

This code correctly shows my dialog, but when I remove the comment where I try to link the "File|Quit" menu with the function exit_action, it breaks.

Any hint how I can connect the menu to the function?


Solution

  • Your code has the following errors:

    • only the attributes can be accessed from outside the class, in your case exit_action is not, in order to be an attribute you must precede it self.

    • in the case of the function exit_action is not defined self, in the classes the first attribute of every method is the instance, which by convention is given the name of self, in the case exit_action should be the widget, for this we can use a lambda function, but you also have to invoke the close function using parentheses.


    frm_main.py

    import sys
    from PyQt5.QtWidgets import QApplication, QMainWindow, QAction
    from PyQt5.QtGui import QIcon
    
    class GUI(QMainWindow):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle('MyApp')
            self.resize(400, 300)
            self.statusBar().showMessage('Welcome')
            self.add_menus()
    
        def add_menus(self):
            menubar = self.menuBar()
            file_menu = menubar.addMenu('&File')
    
            self.exit_action = QAction('&Quit', self)
            file_menu.addAction(self.exit_action) 
    

    main.py

    from frm_main import GUI
    from PyQt5 import QtWidgets
    from PyQt5.QtWidgets import QApplication
    
    def exit_action(widget):
        widget.close()
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = QtWidgets.QMainWindow()
        ui = GUI()
        ui.exit_action.triggered.connect(lambda: exit_action(ui))
        ui.show()
        sys.exit(app.exec_())