1

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_()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Cirrocumulus
  • 520
  • 3
  • 15

1 Answers1

2

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()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you. It did seem weird to me to pass the QApplication object to the App controller. However, when I modify my code to reflect yours, the dialog isn't displayed at all. I don't understand why. – Cirrocumulus Oct 05 '20 at 08:52
  • @Cirrocumulus 1) The app is irrelevant since it is a question of styles. 2) I have provided a functional code that implements what you requested, I am not responsible for its implementation as I do not know it. So if you want more help then provide a [mre] since probably the code you don't want to show is generating the error. – eyllanesc Oct 05 '20 at 08:55
  • You are correct, your suggestion has uncovered another strange issue with how I'm binding the buttons. It's an unrelated problem. Thanks again. – Cirrocumulus Oct 05 '20 at 09:09