Problem with window close/closeEvent
-
I am failing to get a
Quit
button to behave just like clicking on the "window close" "X" icon.There is a bit of precise detail below, but the problem ought really to be simple.
I have inherited a large body of Qt5/PyQt5 code. It is possible I am failing to spot something relevant, but I see the outline as:
class Main(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.actionQuit = QtWidgets.QAction("Quit", self) self.actionQuit.triggered.connect(QtWidgets.QApplication.quit) self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) def closeEvent(self, event): QSettings.setValue("main_geometry", self.saveGeometry()) QSettings.setValue("main_state", self.saveState()) if __name__ == '__main__': main = Main() sys.exit(app.exec_())
As that stands, when I close the main window via the "X" close-icon it does call
closeEvent()
to save state. However, whenQuit
button is clicked theQtWidgets.QApplication.quit
does not invokecloseEvent()
.So having looked at posts like:
- https://forum.qt.io/topic/39699/solved-why-qdialog-does-not-receive-a-closeevent-on-hitting-esc/3
- https://stackoverflow.com/questions/25191954/using-the-closeevent-in-a-qt-application-does-not-close-it
- https://stackoverflow.com/questions/22460003/pyqts-qmainwindow-closeevent-is-never-called
- http://www.qtcentre.org/archive/index.php/t-61003.html
I changed code to
self.actionQuit.triggered.connect(self.close)
, expecting that to work. However, that did not callcloseEvent()
before exiting.On a whim I commented out
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
, then not only iscloseEvent()
not called but the window/application does not close/quit/exit either. So now I don't really understand what connecting the button toself.close
is doing anyway...- Should
self.actionQuit.triggered.connect(self.close)
be all I have to do/work? - Why does it not work for me? Am I omitting some important detail I am not aware of?
-
@JNBarchan said in Problem with window close/closeEvent:
Disclaimer: I do not know Python
then not only is closeEvent() not called
How do you gather this? If this snippet is representative of your code, then you need to accept the event at the end of the
closeEvent
override. Otherwise the widget/window/dialog won't be closed and the program won't exit.Should self.actionQuit.triggered.connect(self.close) be all I have to do/work?
Yes in principle.
-
@kshegunov said in Problem with window close/closeEvent:
@JNBarchan said in Problem with window close/closeEvent:
Disclaimer: I do not know Python
then not only is closeEvent() not called
How do you gather this?
I know this because I place a breakpoint at the start of
closeEvent()
! And it's hit when I close via window's "X" button, but not hit when I click theQuit
button (when I have attachedself.close
as the handler)!If this snippet is representative of your code, then you need to accept the event at the end of the
closeEvent
override.
Otherwise the widget/window/dialog won't be closed and the program won't exit.I could look into that. However, since the event is not called from
Quit
button it's not going to help me here, and when it is called from window's "X" button it all works fine just as-is.... -
Here:
#include <QApplication> #include <QMainWindow> #include <QAction> #include <QTimer> int main(int argc, char *argv[]) { QApplication app(argc, argv); Q_UNUSED(app); QMainWindow window; window.show(); QAction * action = new QAction(&window); QObject::connect(action, &QAction::triggered, &window, &QMainWindow::close); QTimer::singleShot(5000, action, &QAction::trigger); return QApplication::exec(); }
This works for me, meaning that it's not a problem with
close
or connecting. Either yourcloseEvent
is discarded for some reason or the button (which is not visible in your code) is not triggering the action. -
@kshegunov
Thank you for confirming that the principle is correct. I am presently debugging and discovering that theQuit
button has nothing to do with theself.actionQuit = QtWidgets.QAction("Quit", self)
, and has some overridden code elsewhere such that it is doing its ownQtWidgets.QApplication.exit()
and is not connected toself.close()
and henceself.closeEvent()
at all :( Hence the lack of behaviour.I will complete this post in a few minutes, having solved the issue for me. Thank you for your help.
EDIT: So the code I inherited declared an
actionQuit
and connected to a callback (just to fool me), but never actually created it in the menu viaself.toolbar.addAction(self.actionQuit)
. TheQuit
button had code in a different module(!) to just doQtWidgets.QApplication.exit()
, no "closing" at all. Once I traced this down I have made it callclose()
on main window instead and now all is well with that invokingcloseEvent()
.Not my fault existing code is a labyrinthine mess, and I'm new to Qt & Python! Thanks for all help.