Like @ababak mentioned, you can probably use cmds.layoutDialog to create a modal dialog using Maya's built-in Qt wrappers.
However, if you just want to go straight to Qt instead, which I highly recommend, here's some simple scaffolding to get you started:
import shiboken2
import maya.OpenMayaUI as MayaUI
import maya.cmds as cmds
from PySide2 import QtCore, QtGui, QtWidgets
class testModalDialog(QtWidgets.QDialog):
'''Simple QDialog example
Args:
modal (bool, optional): Show a modal window?
autoShow (bool, optional): Auto-show window after creating class instance?
initialSize (tuple (int), optional): Initial dialog size given as (width, height)
parent (QWidget|mixed, optional): Dialog parent. If None, Maya's main window will be used
'''
def __init__(self, modal=True, autoShow=True, initialSize=(600, 300), parent=None):
self.mayaMainWindow = shiboken2.wrapInstance(long(MayaUI.MQtUtil.mainWindow()), QtWidgets.QWidget)
super(testModalDialog, self).__init__(parent or self.mayaMainWindow)
self.setWindowTitle('This is a {} dialog'.format('modal' if modal else 'standard'))
self.resize(initialSize[0], initialSize[1])
# Build UI
self.setupUi()
# Setup connections
self.setupConnections()
# Show dialog if requested
if autoShow and modal:
print('Showing you a modal dialog')
self.exec_()
elif autoShow:
print('Showing you a standard dialog')
self.show()
else:
print('Dialog class is built, but we\'re not automatically showing a dialog. You must manually call the relevant method to display the UI')
def setupUi(self):
'''Populates the UI elements'''
# Main dialog layout
self.layout = QtWidgets.QVBoxLayout()
self.layout.setContentsMargins(3, 3, 3, 3)
self.layout.setSpacing(0)
self.setLayout(self.layout)
# Label
self.label = QtWidgets.QLabel("Hello, I am a label")
self.layout.addWidget(self.label)
# Spacer
self.layout.addItem(
QtWidgets.QSpacerItem(0, 30, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
)
# Button
self.button1 = QtWidgets.QPushButton('I am a button that stretches to full with')
self.layout.addWidget(self.button1)
# Spacer
self.layout.addItem(
QtWidgets.QSpacerItem(0, 30, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
)
# Button
self.button2Layout = QtWidgets.QHBoxLayout()
self.button2Layout.addItem(
QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
)
self.button2 = QtWidgets.QPushButton('And I am a button that only take up as much space as I need')
self.button2Layout.addWidget(self.button2)
self.button2Layout.addItem(
QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
)
self.layout.addLayout(self.button2Layout)
# Spacer to absorb remaining vertical space
# You actually probably don't want this here, just using it as an example to show expanding spacers
self.layout.addItem(
QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
)
def setupConnections(self):
'''Setup all connections like callbacks for button clicks, etc'''
self.button1.clicked.connect(self.button1click)
self.button2.clicked.connect(self.button2click)
def button1click(self, *args):
'''Button 1 has been clicked (callback)'''
self.displayAlert('Button 1', 'You clicked the first button')
def button2click(self, *args):
'''Button 2 has been clicked (callback)'''
self.displayAlert('Button 2', 'You clicked the second button')
def displayAlert(self, title, message):
'''Simple wrapper for cmds.confirmDialog'''
cmds.confirmDialog(message=message, icon='information', title=title, button=["OK"])
print('Running modal')
tester = testModalDialog()
print('Back in main thread. Dialog instance is: {}'.format(tester))
Qt docs might come in handy: https://doc.qt.io/qt-5/reference-overview.html