TheStrangeQuark
TheStrangeQuark

Reputation: 2405

Wait until QtWidgets.QMainWindow is closed before continuing

I have a PyQt5 window that will open a dialog window that I have created that just asked the user to do something and click a button that closes the window. The two windows are made with class RenameDialog(QtWidgets.QMainWindow): and class Prog(QtWidgets.QMainWindow):. and in Prog, I have self.renameDialog = RenameDialog(self). In a piece of the code I have

self.renameDialog.show()
#Other code to run after renameDialog window is closed

But this does not work since I cannot figure out how to wait until renameDialog is closed. I have tried putting self.renameDialog.setWindowModality(QtCore.Qt.WindowModality) before self.renameDialog.show() and I was trying to figure out how to use .exec_() but do not know where I can use this method in this context. Is there a way to wait until this QtWidgets.QMainWindow is hidden or destroyed before continuing the code?

Upvotes: 1

Views: 2167

Answers (2)

RBenet
RBenet

Reputation: 211

Here I leave a small test application to test the different options for a QMainWindow to act as a QDialog.

I have based on this question:

PyQt: Wait until widget closes

and the answer gave me @musicamante in this question:

QMainWindow stop/pause execution, until Window Close (Not QDialog)

Here is my code:

import sys
from PyQt6 import QtCore, QtWidgets

class Ui_FirstWindow(object):
    def setupUi(self, FirstWindow):
        FirstWindow.resize(400, 300)
        self.centralWidget = QtWidgets.QWidget(FirstWindow)
        self.pushButton = QtWidgets.QPushButton(self.centralWidget)
        self.pushButton.setGeometry(QtCore.QRect(110, 130, 191, 23))
        self.pushButton.setText("Load Second Window")
        self.pushButton2 = QtWidgets.QPushButton(self.centralWidget)
        self.pushButton2.setGeometry(QtCore.QRect(110, 170, 191, 23))
        self.pushButton2.setText("LoadThirdWindow")
        self.pushButton4 = QtWidgets.QPushButton(self.centralWidget)
        self.pushButton4.setGeometry(QtCore.QRect(110, 210, 191, 23))
        self.pushButton4.setText("4 Window")
        self.pushButton5 = QtWidgets.QPushButton(self.centralWidget)
        self.pushButton5.setGeometry(QtCore.QRect(110, 250, 191, 23))
        self.pushButton5.setText("5 Window")
        FirstWindow.setCentralWidget(self.centralWidget)
        

    def LoadSecondWindow(self):
        SecondWindow = QtWidgets.QMainWindow()
        ui = Ui_SecondWindow()
        ui.setupUi(SecondWindow)
        SecondWindow.show()
        
class Ui_SecondWindow(object):
    
    def setupUi(self, SecondWindow):
        SecondWindow.resize(400, 300)
        self.centralWidget = QtWidgets.QWidget(SecondWindow)
        self.pushButton = QtWidgets.QPushButton(self.centralWidget)
        self.pushButton.setGeometry(QtCore.QRect(110, 130, 191, 23))
        SecondWindow.setCentralWidget(self.centralWidget)
        self.pushButton.setText('PushButton')
        
class Controller:

    def __init__(self):
        pass

    def Show_FirstWindow(self):

        self.FirstWindow = QtWidgets.QMainWindow()
        self.ui = Ui_FirstWindow()
        self.ui.setupUi(self.FirstWindow)
        self.ui.pushButton.clicked.connect(self.Show_SecondWindow)
        self.ui.pushButton2.clicked.connect(self.Show_ThirdWindow)
        self.ui.pushButton4.clicked.connect(self.Show_4Window)
        self.ui.pushButton5.clicked.connect(self.Show_5Window)
        
        self.FirstWindow.show()

    def Show_SecondWindow(self):
        
        self.SecondWindow = QtWidgets.QMainWindow()
        
        self.ui = Ui_SecondWindow()
        self.ui.setupUi(self.SecondWindow)
       
        self.SecondWindow.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
        self.SecondWindow.show()
        print("Don't Stop")
        
    def Show_ThirdWindow(self):
        self.ThirdWindow = QtWidgets.QDialog()
        self.ThirdWindow.exec()
        print('Yess Stop Window 3')

    def Show_4Window(self):
        # https://stackoverflow.com/questions/19462112/pyqt-wait-until-widget-closes
        self.widget = QtWidgets.QMainWindow()
        self.widget.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
        self.widget.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
        self.widget.show()
        loop = QtCore.QEventLoop()
        self.widget.destroyed.connect(loop.quit)
        loop.exec() # wait ...
        print('Yes Stop Window 4')
    
    def Show_5Window(self):
        def action5(self):
            print('Yes Stop Window 5')
            
        self.window5 = QtWidgets.QMainWindow()
        
        self.ui = Ui_SecondWindow()
        self.ui.setupUi(self.window5)
        self.window5.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
        self.window5.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
        self.window5.show()
        self.window5.destroyed.connect(action5)
        

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    Controller = Controller()
    Controller.Show_FirstWindow()
    sys.exit(app.exec())

Upvotes: 0

MrLeeh
MrLeeh

Reputation: 5589

You have two possibities here.

1.You can set the dialog as modal. In this case any other interaction with the GUI is blocked until the user closes the dialog. Only then the code is continued. You need to inherit from QDialog for this to work:

class RenameDialog(QDialog):
    # ...
    pass

class YourMainWindow(QMainWindow):
    def show_dlg(self):
        dlg = RenameDialog(self)
        res = dlg.exec()
        if res == QDialog.Accepted:
            print('Accepted')
        else:
            print('Rejected')
  1. Connect to the finished() signal of your dialog. This way the dialog does not have to be modal and you can still interact with the rest of your GUI. When the user closes the dialog the finished signal gets triggered and the connected callback function gets called.

Upvotes: 4

Related Questions