Important: Please read the Qt Code of Conduct -

QDialog, Qt::ApplicationModal, open() vs exec(),

  • Qt 5.7. PyQt (should not be relevant). Ubuntu 17.04 with default Unity desktop (might or might not be relevant). Cannot test under Windows.

    I'm playing around trying to understand if there is any significance to the inconsistent fact that the code I have inherited sometime uses QDialog.exec() and sometimes uses

    I know that both set the dialog modal. I know that the difference is that open() allows my code to continue (if it wants to do anything) while exec() blocks. (I suspect in my code usage is random, in that it doesn't actually do anything after open(), but not sure yet.)

    I thought exec() would just go open() and then enter a blocking loop, and that was it. However, read on....

    I am seeing some seemingly odd behaviour(?) from open() but not exec() if I choose to set Qt::ApplicationModal.

        def btn1_on_clicked(self):
            dlg = QtWidgets.QDialog()
            # Next line ensures we have a reference to dialog if we call,
            # so we don't have any "out-of-scope-reference" issue
            # but can be removed without affecting the behaviour below
            self.dlg = dlg
            print("Before setWindowModality is modal: ", dlg.isModal())
            print("Before setWindowModality modality: ", dlg.windowModality())
            print("Before open is modal: ", dlg.isModal())
            print("Before open modality: ", dlg.windowModality())
            print("After open is modal: ", dlg.isModal())
            print("After open modality: ", dlg.windowModality())

    Run the above and I get:

    Before setWindowModality is modal:  False
    Before setWindowModality modality:  0
    Before open is modal:  True
    Before open modality:  2
    After open is modal:  True
    After open modality:  2

    Hunky-dory. Now change dlg.exec() to There is only one change, to the final line of output:

    After open modality:  1

    So, exec() retains my setWindowModality(QtCore.Qt.ApplicationModal), but open() alters it to Qt::WindowModal.



    • Since open() has change to window-modal, and no parent window was specified, there is no modality against the invoking window
    • exec() does block the invoking window. But as a separate observation: sometimes (mostly?) clicking on invoker causes nothing visual (good), but sometimes you see the back window come up-front and then the modal dialog comes back up-front a moment later (ugly). Nothing to do with where you click, probably more like a timing thing. Perhaps Windows is better at this but Linux desktop manager/X11 is not offering application-modality and so Qt has to kludge it itself?

  • Any comment from anyone on this one? So but not exec() alters dialog from QtCore.Qt.ApplicationModal to Qt::WindowModal, but docs don't tell you this?

  • Lifetime Qt Champion


    That's because open is not blocking, so you are printing the "current state", you should connect the finished signal and only print there the modality. You'll see it matches what's advertised.

  • @SGaist
    Thanks for the reply. I can't say I understand (yes, open() is non-modal, but what has that got to do with application vs parent window modality?). However I don't have a usage case at present so I'll just leave it.

  • Lifetime Qt Champion

    By default open shows the dialog as window modal as explained in the slot documentation. Now what happens with your code is that open is called which means that the dialog will be shown as soon as possible (not immediately even if it feels like that) but between the moment open is called and the dialog is shown, the print statements will have been executed..

  • @SGaist
    Ohhh, I see! Thanks :)

  • Its just async behaviour with open()

    From Qt's docs:

    Avoid using this function; instead, use open(). Unlike exec(), open() is asynchronous, and does not spin an additional event loop. This prevents a series of dangerous bugs from happening (e.g. deleting the dialog's parent while the dialog is open via exec()). When using open() you can connect to the finished() signal of QDialog to be notified when the dialog is closed.

Log in to reply