Devon Cornwall
Devon Cornwall

Reputation: 957

Close PyQt App via a Modal Dialog

I am currently coding an application using the Qt4 python bindings that requires the user to provide login credentials. At startup of my application I show a modal dialog in which the user can enter their data. Since the application cannot provide useful services when the user is not logged in, I want to close the app if the user clicks the cancel button.

So, if the dialog returns a negative result, I just call the close() method of my QMainWindow. Normally this leads to the exit of the application since there are no interactable windows any more.

However, if the modal Dialog has been shown before, the application simply continues to run and I have to kill it manually.

Below is the code for an minimal example

main.py:

import sys
from PyQt4.QtGui import QApplication
from MyMainWindow import MyMainWindow

app = QApplication(sys.argv)

window = MyMainWindow()
window.show()

app.exec_()

print "Terminated"

MyMainWindow.py:

from PyQt4.QtGui import QMainWindow
from PyQt4 import QtGui
from MyDialog import MyDialog

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.setWindowTitle("Close App Test")

        self.centralwidget = QtGui.QWidget(self)
        self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)

        self.closeButton = QtGui.QPushButton(self.centralwidget)
        self.closeButton.setText("Close")

        self.closeButton.clicked.connect(self.exit)

    def show(self):
        QMainWindow.show(self)

        myDialog = MyDialog(self) 
        res = myDialog.exec_()  

        if res == 0:
            self.exit()
        else:
            print "Continue"

    def exit(self):
        self.close()

MyDialog.py:

from PyQt4.QtGui import QDialog
from PyQt4 import QtGui

class MyDialog(QDialog):

    def __init__(self, parent = None):
        QDialog.__init__(self, parent)

        self.setWindowTitle("Modal Dialog")

        self.resize(200, 50)

        self.closeButton = QtGui.QPushButton(self)
        self.closeButton.setText("Close")
        self.closeButton.move(10, 10)

        self.otherButton = QtGui.QPushButton(self)
        self.otherButton.setText("Do Nothing")
        self.otherButton.move(100, 10)

        self.closeButton.clicked.connect(self.reject)
        self.otherButton.clicked.connect(self.accept)

If the Close button on the modal dialog is clicked, the application continues to run even if all windows are closed. If the "Do Nothing" button is clicked, and the application is closed with the close button on the main window, everything works as expected and the application terminates.

I cannot really see the difference between both cases, since each time I just call close on the main window. I can just assume that I have errors in handling the modal dialog. I even tried tinkering around with myDialog.close(), myDialog.destroy(), as well as the quitOnCloseand deleteOnClose window attributes without any positive effects.

Any help is appreciated.

Upvotes: 0

Views: 2136

Answers (1)

West
West

Reputation: 86

self.exit() is called before app.exec_() if the Close button on the modal dialog is clicked, so the application continues to run. self.exit() should be called when the main event loop is running.

The following is a possible solution for the case:

from PyQt4.QtGui import QMainWindow
from PyQt4 import QtGui
from pyQt4 import QtCore

from MyDialog import MyDialog

class MyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.setWindowTitle("Close App Test")

        self.centralwidget = QtGui.QWidget(self)
        self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)

        self.closeButton = QtGui.QPushButton(self.centralwidget)
        self.closeButton.setText("Close")

        self.closeButton.clicked.connect(self.exit)

    def login(self):
        myDialog = MyDialog(self) 
        res = myDialog.exec_()  

        if res == 0:
            self.exit()
        else:
            print "Continue"

    def show(self):
        QMainWindow.show(self)
        QtCore.QTimer.singleShot(0, self.login)        

    def exit(self):
        self.close()

Upvotes: 1

Related Questions