On launch, my Qt application displays a dialog box with some options, before displaying the main window. The dialog box has a ‘Start’ and ‘Cancel’ button. The same dialog box is used at a later time, after the main window is displayed, when the user clicks on a ‘New Game’ button.
I’m trying to have the ‘Cancel’ button quit the application if it’s the only interface element being displayed (i.e. on application launch). In my current code, however, the main window is still displayed.
If I replace self.view.destroy()
with self.view.deleteLater()
the main window briefly flashes into existence before disappearing (and quitting properly), but this can’t be the solution.
If I move the view.show()
call inside the dialog.exec_()
block, it doesn’t work either. Mainly because I would be calling view.show()
every time the dialog is displayed again from within the main window, but also because even in this case the app doesn’t really quit. The main window, in this case, is not displayed but the process is keeps running (Python application icon still visible in the Dock).
What am I doing wrong here? I’ve read other similar questions but I don’t understand how to apply these solutions in my case.
(PySide2 5.15.1 on macOS 10.15.6)
class App: def __init__(self, app, game, view): self.app = app self.game = game self.view = view # Display the dialog # Same callback is bound to a QPushButton in MainWindow self.cb_start_dialog() def cb_start_dialog(self): # Do some initialisation dialog = DialogNewGame() # A subclass of QDialog if dialog.exec_(): # Setup the interface else: if not self.view.isVisible(): # Condition evaluates correctly # (False on app launch, # True if main window is displayed) self.view.destroy() self.app.quit() # Doesn't work, main window still displayed def main(): application = QApplication() view = MainWindow() # A QWidget with the main window model = Game() # Application logic App(application, model, view) view.show() application.exec_()
Advertisement
Answer
If the code is analyzed well, it is observed that “quit” is invoked before the eventloop starts, so it makes no sense to terminate an eventloop that never started. The solution is to invoke X an instant after the eventloop starts. On the other hand, the quit method is static so it is not necessary to access “self.app”
from PySide2.QtCore import QTimer from PySide2.QtWidgets import QApplication, QDialog, QMainWindow class MainWindow(QMainWindow): pass class DialogNewGame(QDialog): pass class Game: pass class App: def __init__(self, game, view): self.game = game self.view = view QTimer.singleShot(0, self.cb_start_dialog) def cb_start_dialog(self): dialog = DialogNewGame() if dialog.exec_(): pass else: QApplication.quit() def main(): application = QApplication() view = MainWindow() model = Game() app = App(model, view) view.show() application.exec_() if __name__ == "__main__": main()