1

I am developping a GUI using PyQt based on the MVC model. So I have 3 files:

view.py
model.py
controller.py

I would like to execute a method from the controller when the user quit the GUI, so when it catchs the CloseEvent.

A brief of a similar code looks like this:


from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import sys

class window(QMainWindow):
    def __init(self):
        super().__init__()

    def closeEvent(self, evnt):
        self.exit_msg = QMessageBox.question(
                self, 'Avant de quitter', 'Would you like to save before leaving ?',
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)

        if self.exit_msg == QMessageBox.Yes:
            ctrl.done()
            evnt.accept()
        elif self.exit_msg == QMessageBox.No:
            evnt.accept()
        else:
            evnt.ignore()


class ctrl():
    def __init__(self, view):
        self._view = view

    def done(self):
        print('I sent the mail')

def main():
    app = QApplication(sys.argv)
    view = window()
    view.show()
    controller = ctrl(view = view)

    app.exec()

if __name__ == '__main__':
        main()

Of course the ctrl.done() line does not work but it represents what I would like to do.

I implemented it in the window class in the first place, but I need data from the model file, so it broke the MVC model because I did not find a way to make the controller communicate the right informations between the model and the view using the controller.

The main thing to remember is that I want the GUI to send a mail (method done() in the example) when the user click Yes on the exit_msg. This mail contain data from the model class. How do I do it ?

Can you help me please ?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Francky380
  • 233
  • 1
  • 12

1 Answers1

1

You have to use a QObject to monitor the events of the view, and accordingly implement the logic you want, and for that you can create another class that inherits from QObject and notifies the Controller, or that the Controller is the QObject that monitors directly, in this case, implement the second option

import sys

from PyQt5.QtCore import QEvent, QObject
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox


class Window(QMainWindow):
    pass


class Controller(QObject):
    def __init__(self, view, parent=None):
        super().__init__(parent)
        self._view = view

        self.view.installEventFilter(self)

    @property
    def view(self):
        return self._view

    def eventFilter(self, obj, event):
        if self.view is obj and event.type() == QEvent.Close:
            exit_msg = QMessageBox.question(
                self.view,
                "Avant de quitter",
                "Would you like to save before leaving ?",
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
            )
            if exit_msg == QMessageBox.Yes:
                self.done()
            elif exit_msg == QMessageBox.Cancel:
                event.ignore()
                return True
        return super().eventFilter(obj, event)

    def done(self):
        print("I sent the mail")


def main():
    app = QApplication(sys.argv)
    view = Window()
    view.show()
    controller = Controller(view=view)
    app.exec()


if __name__ == "__main__":
    main()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Works exactly as I wanted, thanks. Question however, why the view(self) function ? And why is it decorated with @property ? Can't I use self._view ? Is it a more reliable way of doing things ? – Francky380 Dec 20 '19 at 15:21
  • @Francky380 read https://stackoverflow.com/questions/6618002/using-property-versus-getters-and-setters – eyllanesc Dec 20 '19 at 23:38
  • Thank, I read it with attention. I also read "a lot" about @property and property in general but still, I do not understand why it is wise here to use it? Should I use self.view.XX.setText('a text') instead of self._view.XX.setText('a text') in my code in general ? – Francky380 Dec 22 '19 at 18:00