Application not shutting down properly when (x) button is clicked.
-
wrote on 2 Aug 2024, 13:59 last edited by
I've created a window in Qt for Python by loading a ui file in the following way:
import sys from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtCore import QFile class MainWindow(QMainWindow): def __init__(self, app): super().__init__() self.app = app loader = QUiLoader() file = QFile("mainWindow.ui") file.open(QFile.ReadOnly) self.ui = loader.load(file, self) file.close() self.ui.show() def closeEvent(self, event): print("Close event triggered") self.app.quit() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow(app) app.aboutToQuit.connect(lambda: print("quit")) sys.exit(app.exec())
I've overrided the closeEvent() method to try to get "Close event triggered" to print out. I've also connected the aboutToQuit signal to a lambda function which prints out "quit". However, when I press the (x) button, neither "quit" nor "Close event triggered" is printed, and the terminal process keeps running. So what am I doing wrong here? I'm on Ubuntu, and here is my ui file, if that helps:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>953</width> <height>681</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralWidget"> <layout class="QHBoxLayout" name="horizontalLayout"/> </widget> <widget class="QMenuBar" name="menuBar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>953</width> <height>22</height> </rect> </property> </widget> </widget> <resources/> <connections/> </ui>
-
I've created a window in Qt for Python by loading a ui file in the following way:
import sys from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtCore import QFile class MainWindow(QMainWindow): def __init__(self, app): super().__init__() self.app = app loader = QUiLoader() file = QFile("mainWindow.ui") file.open(QFile.ReadOnly) self.ui = loader.load(file, self) file.close() self.ui.show() def closeEvent(self, event): print("Close event triggered") self.app.quit() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow(app) app.aboutToQuit.connect(lambda: print("quit")) sys.exit(app.exec())
I've overrided the closeEvent() method to try to get "Close event triggered" to print out. I've also connected the aboutToQuit signal to a lambda function which prints out "quit". However, when I press the (x) button, neither "quit" nor "Close event triggered" is printed, and the terminal process keeps running. So what am I doing wrong here? I'm on Ubuntu, and here is my ui file, if that helps:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>953</width> <height>681</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralWidget"> <layout class="QHBoxLayout" name="horizontalLayout"/> </widget> <widget class="QMenuBar" name="menuBar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>953</width> <height>22</height> </rect> </property> </widget> </widget> <resources/> <connections/> </ui>
wrote on 2 Aug 2024, 14:55 last edited by JonB 8 Feb 2024, 14:56@tbreimer said in Application not shutting down properly when (x) button is clicked.:
and the terminal process keeps running.
What "terminal" process"? You have created a
QApplication
and shown aQMainWindow
, so this application is not running in a terminal.Start by removing your
closeEvent()
andself.app.quit()
, does your application exit when the main window is closed? Not that it matters, but get rid of yourMainWindow
and using the.ui
file, just verify it exits with a plainQMainWindow
and nothing else. -
Hi,
Just did a quick test with:
import sys from PySide6.QtWidgets import QApplication, QMainWindow class MainWindow(QMainWindow): def __init__(self): super().__init__() def closeEvent(self, event): print("Close event triggered") super().closeEvent(event) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() app.aboutToQuit.connect(lambda: print("quit")) sys.exit(app.exec())
It's working properly on macOS 13.6.8 with PySide6 6.7.2
-
@tbreimer said in Application not shutting down properly when (x) button is clicked.:
and the terminal process keeps running.
What "terminal" process"? You have created a
QApplication
and shown aQMainWindow
, so this application is not running in a terminal.Start by removing your
closeEvent()
andself.app.quit()
, does your application exit when the main window is closed? Not that it matters, but get rid of yourMainWindow
and using the.ui
file, just verify it exits with a plainQMainWindow
and nothing else.wrote on 5 Aug 2024, 14:43 last edited by@JonB said in Application not shutting down properly when (x) button is clicked.:
What "terminal" process"?
By this I mean that if I run the command
python3 ./main.py
in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.Using a normal
QMainWindow
object does solve the issue, with the process ending once the window is closed. Here's a video demonstrating this, which is my desired behavior. This quitting behavior also works when loading a ui file and setting it as the central widget to aQMainWindow
in the following way:import sys from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtUiTools import QUiLoader from PySide6.QtCore import QFile if __name__ == "__main__": app = QApplication(sys.argv) window = QMainWindow() loader = QUiLoader() file = QFile("mainWindow.ui") file.open(QFile.ReadOnly) ui = loader.load(file) window.setCentralWidget(ui) window.show() app.aboutToQuit.connect(lambda: print("quit")) sys.exit(app.exec())
So, the issue seems to related to my custom
MainWindow
class. However, I'm still confused as to whycloseEvent()
fails to run and "quit" fails to print in my original code. -
@JonB said in Application not shutting down properly when (x) button is clicked.:
What "terminal" process"?
By this I mean that if I run the command
python3 ./main.py
in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.Using a normal
QMainWindow
object does solve the issue, with the process ending once the window is closed. Here's a video demonstrating this, which is my desired behavior. This quitting behavior also works when loading a ui file and setting it as the central widget to aQMainWindow
in the following way:import sys from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtUiTools import QUiLoader from PySide6.QtCore import QFile if __name__ == "__main__": app = QApplication(sys.argv) window = QMainWindow() loader = QUiLoader() file = QFile("mainWindow.ui") file.open(QFile.ReadOnly) ui = loader.load(file) window.setCentralWidget(ui) window.show() app.aboutToQuit.connect(lambda: print("quit")) sys.exit(app.exec())
So, the issue seems to related to my custom
MainWindow
class. However, I'm still confused as to whycloseEvent()
fails to run and "quit" fails to print in my original code.wrote on 5 Aug 2024, 15:21 last edited by -
@JonB said in Application not shutting down properly when (x) button is clicked.:
What "terminal" process"?
By this I mean that if I run the command
python3 ./main.py
in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.Using a normal
QMainWindow
object does solve the issue, with the process ending once the window is closed. Here's a video demonstrating this, which is my desired behavior. This quitting behavior also works when loading a ui file and setting it as the central widget to aQMainWindow
in the following way:import sys from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtUiTools import QUiLoader from PySide6.QtCore import QFile if __name__ == "__main__": app = QApplication(sys.argv) window = QMainWindow() loader = QUiLoader() file = QFile("mainWindow.ui") file.open(QFile.ReadOnly) ui = loader.load(file) window.setCentralWidget(ui) window.show() app.aboutToQuit.connect(lambda: print("quit")) sys.exit(app.exec())
So, the issue seems to related to my custom
MainWindow
class. However, I'm still confused as to whycloseEvent()
fails to run and "quit" fails to print in my original code.@tbreimer said in Application not shutting down properly when (x) button is clicked.:
@JonB said in Application not shutting down properly when (x) button is clicked.:
What "terminal" process"?
By this I mean that if I run the command
python3 ./main.py
in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.You can't enter new commands because you have the Qt event loop running which is normal. You would have the same result starting any GUI enabled application from the command line. You would also have the same result if using for example
tail -f /var/log/syslog
as the tail process will continue to work in the foreground. -
@tbreimer said in Application not shutting down properly when (x) button is clicked.:
@JonB said in Application not shutting down properly when (x) button is clicked.:
What "terminal" process"?
By this I mean that if I run the command
python3 ./main.py
in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.You can't enter new commands because you have the Qt event loop running which is normal. You would have the same result starting any GUI enabled application from the command line. You would also have the same result if using for example
tail -f /var/log/syslog
as the tail process will continue to work in the foreground.wrote on 6 Aug 2024, 13:07 last edited by@SGaist said in Application not shutting down properly when (x) button is clicked.:
You can't enter new commands because you have the Qt event loop running which is normal.
I understand that, but compare this behavior to this. In the first one, the event loop keeps running indefinitely after the window is closed, and is only stopped with a manual control-z to suspend the process. In the second example, the event loops automatically ends after the window is closed and the process also ends.
-
wrote on 6 Aug 2024, 13:18 last edited by tbreimer 8 Jun 2024, 13:23
@JonB said in Application not shutting down properly when (x) button is clicked.:
@SGaist shows code which subclasses QMainWindow, overrides closeEvent() and works for him. Does his code work for you?
It does! And I also figured out the problem, @JonB's hunch about it being related to the
loader.load()
was spot on. In my original code, I was using theQUILoader
to load the ui file and set it's parent toMainWindow
. Then, I was showing theQWidget
retuned by the loader, like so:self.ui = loader.load(file, self) self.ui.show()
What I needed to do is set
self.ui
as the central widget ofMainWindow
, and then callMainWindow.show()
. This example works to subclassQMainWindow
, load a ui file, override thecloseEvent
method, and properly shutdown when the window is closed.import sys from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtUiTools import QUiLoader from PySide6.QtCore import QFile class MainWindow(QMainWindow): def __init__(self): super().__init__() loader = QUiLoader() file = QFile("mainWindow.ui") file.open(QFile.ReadOnly) ui = loader.load(file) self.setCentralWidget(ui) self.show() def closeEvent(self, event): print("Close event triggered") super().closeEvent(event) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec())
Thanks for the help everyone!
-
-
@JonB said in Application not shutting down properly when (x) button is clicked.:
@SGaist shows code which subclasses QMainWindow, overrides closeEvent() and works for him. Does his code work for you?
It does! And I also figured out the problem, @JonB's hunch about it being related to the
loader.load()
was spot on. In my original code, I was using theQUILoader
to load the ui file and set it's parent toMainWindow
. Then, I was showing theQWidget
retuned by the loader, like so:self.ui = loader.load(file, self) self.ui.show()
What I needed to do is set
self.ui
as the central widget ofMainWindow
, and then callMainWindow.show()
. This example works to subclassQMainWindow
, load a ui file, override thecloseEvent
method, and properly shutdown when the window is closed.import sys from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtUiTools import QUiLoader from PySide6.QtCore import QFile class MainWindow(QMainWindow): def __init__(self): super().__init__() loader = QUiLoader() file = QFile("mainWindow.ui") file.open(QFile.ReadOnly) ui = loader.load(file) self.setCentralWidget(ui) self.show() def closeEvent(self, event): print("Close event triggered") super().closeEvent(event) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec())
Thanks for the help everyone!
wrote on 6 Aug 2024, 13:48 last edited by@tbreimer
Glad I could help. It's your choice, but why do you use thisQUILoader
/loading stuff at all? Like I said, I never have. So far as I can see, when you do so you lost all ability to address the widgets you design directly by Python variable, don't you have toQObject::findChild<>()
to get at them? I always use Option A: Generating a Python class rather than Option B, much better editing experience as well as coding? And what everyone in C++ does. Have you looked at it or just settled for the loader approach? -
wrote on 6 Aug 2024, 14:03 last edited by
@JonB I see what you mean, and yes I have to do
QObject::findChild<>()
to get every widget. I suppose when I was initially learning Qt for Python I just thought it would be easier to forgo the extra step of using thepyside6-uic
tool every time I made changes to the ui file. But I agree in retrospect that Option A is better. -
@JonB I see what you mean, and yes I have to do
QObject::findChild<>()
to get every widget. I suppose when I was initially learning Qt for Python I just thought it would be easier to forgo the extra step of using thepyside6-uic
tool every time I made changes to the ui file. But I agree in retrospect that Option A is better.wrote on 6 Aug 2024, 14:43 last edited by JonB 8 Jun 2024, 14:44@tbreimer
Yes, the extra step is irritating (I don't know, I think Creator can call it automatically (when.ui
is changed) for you for Python? It does so for C++) but it's so worth it! Not only nicer code, but also design-time code completion when using the generated variables and the editor knows about their types.
1/11