Keeping Your Main Window Open After Closing a Dialog in PyQt6

Why your app closes when you dismiss a dialog, and how to fix it
Heads up! You've already completed this tutorial.

I'm working with dialogs in PyQt6, and when I press either Accept or Cancel, the entire application closes. How can I prevent this?

When you create and display a dialog (for example, using QDialog.exec()), the dialog runs its own local event loop. Once you click OK or Cancel, the dialog closes and exec() returns a result. At that point, your code continues executing whatever comes after the dialog call.

If there's no main window being shown and no main event loop running, the application simply has nothing left to do — so it exits.

In other words, the dialog is your entire application. Once it's gone, everything shuts down.

The Fix: Run a Main Window with an Event Loop

To keep your application alive after the dialog closes, you need a main window that stays open and a properly running event loop. The dialog should be launched from that main window, so that when the dialog is dismissed, control returns to the main window which is still visible and active.

Here's a minimal complete example that demonstrates the correct setup:

python
import sys

from PyQt6.QtWidgets import (
    QApplication, QDialog, QDialogButtonBox,
    QMainWindow, QPushButton, QVBoxLayout,
)


class CustomDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("My Dialog")

        buttons = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
        self.button_box = QDialogButtonBox(buttons)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        layout = QVBoxLayout()
        layout.addWidget(self.button_box)
        self.setLayout(layout)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Main Window")

        button = QPushButton("Open Dialog")
        button.clicked.connect(self.open_dialog)
        self.setCentralWidget(button)

    def open_dialog(self):
        dialog = CustomDialog(self)
        result = dialog.exec()

        if result == QDialog.DialogCode.Accepted:
            print("User clicked OK")
        else:
            print("User clicked Cancel")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

Let's walk through what's happening here.

The Main Window

The MainWindow class creates a simple window with a single button. When you click that button, it calls open_dialog(), which creates an instance of CustomDialog and displays it using exec().

Once you accept or cancel the dialog, exec() returns and you're back inside the open_dialog method. The main window is still visible and responsive — you can click the button again to reopen the dialog as many times as you like. If you're new to building windows in PyQt6, see our tutorial on creating your first window.

The Event Loop

The block at the bottom of the script is what keeps everything running:

python
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

QApplication manages the main event loop for your application. Calling app.exec() starts that loop, which keeps the application alive, processing user input, repainting widgets, and handling signals and slots. The application will only exit when you close the main window (or explicitly call app.quit()).

Without this event loop, your script runs top-to-bottom and exits as soon as it reaches the end — which is exactly the behavior you'd see if a dialog was the only thing in your script.

Passing self as Parent

You might have noticed that we pass self when creating the dialog:

python
dialog = CustomDialog(self)

This sets the main window as the dialog's parent. It means the dialog will appear centered over the main window and will be properly tied to it in terms of window management. It's a good habit to set a parent for your dialogs whenever you can.

Summary

If your app is closing when you dismiss a dialog, make sure you have:

  1. A QApplication instance with its event loop running via app.exec().
  2. A main window that is shown using .show().
  3. Your dialog launched from within that main window, so control returns to it after the dialog is dismissed.

With this structure in place, your dialogs will open and close without affecting the rest of your application. If you want to open additional windows beyond dialogs, take a look at our guide on creating multiple windows in PyQt6.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

PyQt/PySide 1:1 Coaching with Martin Fitzpatrick

Save yourself time and frustration. Get one on one help with your Python GUI projects. Working together with you I'll identify issues and suggest fixes, from bugs and usability to architecture and maintainability.

Book Now 60 mins ($195)

Martin Fitzpatrick

Keeping Your Main Window Open After Closing a Dialog in PyQt6 was written by Martin Fitzpatrick.

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.