Skip to content
Advertisement

How to quit Qt application before main window is displayed

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()
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement