pythonqtpysidemayaqapplication

Maya wait for Qt window to close


Normally in Qt applications you would use this at the start and end of your code:

app = QtWidgets.QApplication(sys.argv)
...
app.exec_()

But in Maya, you don't use this because Qt runs on the Maya application it self. I'm sure this works the same for many other applications as well if you don't know what Maya is. That said, my code looks like this:

import sys
from PySide2 import QtWidgets, QtGui, QtCore

class Test():
    def __init__(self):
        self.open_qt()

    def open_qt(self):
        # app = QtWidgets.QApplication(sys.argv) # Don't need this in Maya
        self.window = QtWidgets.QWidget() # I tried QDialog also

        btn = QtWidgets.QPushButton("press me")
        btn.clicked.connect(self.login)

        lay = QtWidgets.QVBoxLayout()
        lay.addWidget(btn)

        self.window.setLayout(lay)
        self.window.show()

        # app.exec_() # Don't need this in Maya

    def login(self):
        print("logged in!")

print("before")
temp = Test()
print("after")

But running this in Maya I get this result:

before
after
logged in!

But I need it to be:

before
logged in!
after

If you run this code outside of Maya (and you use those two commented out lines) then you get the correct result (block above here).

How can I get the Maya Qt to also wait correctly like it would if you used QtWidgets.QApplication(sys.argv)?


Solution

  • A QDialog might be more well suited for your needs, as it runs its own event loop that won't block the program, while waiting for the dialog to be completed.

    The important thing to do is to call of its exec_() and call accept() when needed.

    from PySide2 import QtWidgets, QtGui, QtCore
    
    class Test(QtWidgets.QDialog):
        def __init__(self, parent=None):
            super(Test, self).__init__(parent)
            layout = QtWidgets.QVBoxLayout(self)
    
            self.spinBox = QtWidgets.QSpinBox()
            layout.addWidget(self.spinBox)
    
            btn = QtWidgets.QPushButton("press me")
            layout.addWidget(btn)
            btn.clicked.connect(self.login)
    
        def login(self):
            print("logged in!")
            self.accept()
    
    
    dialog = Test()
    if dialog.exec_():
        print(dialog.spinBox.value())
    

    I don't have Maya, but according to this answer you can get its main window using the maya.OpenMayaUI module and shiboken's wrapInstance().