Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

PySide2, Qt Creator, how to override MainWindow.closeEvent()?



  • I need to confirm close main window when unsaved changes user may want to save.

    The normal way to do this is sub-class from QMainWindow and override closeEvent(). However, I do not begin to understand how to do this from my environment:

    • We use Qt Designer, so it produces the class:
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    

    That goes into mainwindow.cpp. But I don't think that is used in PySide2 environment. It processes the mainwindow.ui file via pyside2-uic to produce mainwindow.py. That in turn then has # WARNING! All changes made in this file will be lost!, so I can't alter that.

    • I can't alter the original .cpp (even if I wanted to), as I shall be wanting to call a Python/PySide2 function in the override of QMainWindow.closeEvent(), this all needs to be done at the Python/Pyside2 side, not C++.

    So I am lost here: how am I supposed to override QMainWindow.closeEvent() or MainWindow.closeEvent() from Python, given that it is not my code which is producing the MainWindow class derived from QMainWindow??

    For now, I am having a go at https://stackoverflow.com/a/53102880/489865. There the poster recognises the problem in a QUiLoader situation from Python, where he says

    But for this it is necessary to inherit from the class, but in your case it is not possible so there is another solution, install an event filter:

    I do not have QUiLoader in code, but I'm thinking nonetheless I am facing a similar problem(?). Should I stick with that approach of MainWindow.installEventFilter, or is there a neater way of overriding MainWindow.closeEvent() here? I might still need the latter if at a future date I need to override a different method....


  • Banned

    Yet another pain with using that Qt-Designer -- my first bit of advise is stop using the Qt-Designer as you are probably not using it for what it was meant to be used for. Further if you code Python-Qt the way it was meant to be coded (which btw the Qt-Designer does not do) then not only will you have code that you can work with -- you will fully understand what it is doing -- aka no surprises -- and lastly you can easily work with it when you need to make changes such as the one you listed.

    If you want to understand how to use Python-Qt the way it was meant to and learn just how simple and easy it is to use I can teach you here or in my free classroom. But if you wish to stay with the Qt-Designer then I cannot help you as that is one major headache I am choosing not to deal with.



  • @Denni-0
    Hi Denni. I know your views about Qt Designer. This one is not up to me, I'm working on someone else's project where it is to be used for design time whether you or I agree that is a good idea or not! I do know it would have been easy in non-designer code, I've sub-classed and overridden from there before, but that's a not a choice in this instance.


  • Banned

    Well your problem is you need to sub-class that UI -- have you actually tried simply sub-classing it?

    CodeWindow::CodeWindow(MainWindow *parent) :

    And I mean no offense by my comments as I do not pay that much attention to who posted the question -- I just answer the question in a consistent manner



  • @Denni-0
    That would be sub-classing at the C++ side. That won't help me, it was sub-classing at the Python side I was looking for, but where I couldn't.... It gets complicated!


  • Banned

    Okay so have you tried

    CodeWindow(MainWindow) :
        def __init__(self):
            MainWindow.__init__(self)
    

    I mean are not all the Qt classes written in C++ and PyQt just wraps them into Python? If the above does not work then perhaps you can look into how PyQt wraps a Qt class



  • Since I posted this question I have come to realize that things are different from what I thought.

    Although using Qt Creator to design the UI generates a mainwindow.cpp file in which MainWindow is a subclass of QMainWindow, my assumption that the generated mainwindow.py would work the same way seems to be erroneous. Instead I found the code was creating its own explicit QMainWindow() and then passing that to generated code to fill with the settings from mainwindow.ui file.

    I do not know whether that is how it's all supposed to be configured, or whether that is indeed different from the C++ approach, but that's what I see in the code I have.

    Anyway, the end result is that means I can create my own Python subclass of QMainWindow and pass that instance to the code generated for setting the stuff from Qt Creator. So I can override closeEvent() easily.


  • Banned

    Awesome glad to hear you got that resolved



  • In docs https://doc.qt.io/qtforpython/tutorials/basictutorial/uifiles.html#generating-a-python-class we are shown creating a class

    class MainWindow(QMainWindow):
    

    I thought the pyuic produced this class definition, and same for uic with C++. That is what I expected. I think not now. You are supposed to write that yourself. They only produce Ui_MainWindow class. Right?

    It turns out the code I am working on does not take that approach, hence my confusion. It does not create any MainWindow class at all. Instead it creates a plain QMainWindow instance and then passes that to the generated Ui_MainWindow.setupUi(). That changes the issue for me, I shall have to ask the author why that approach was adopted....

    EDIT OK, he said "no reason". So now I am free to create my own subclass of QMainWindow in code, and thereby override closeEvent() as required.


Log in to reply