Python Tools - Session 12A

Qt Template UI with Button Callbacks

2020.03.31 - Session 12A

Session Navigation

Overview

This session introduces a reusable Qt template for building Maya tool UIs. Using PySide2's QUiLoader, we load a .ui file created in Qt Designer and wire up button click callbacks to Python methods. The template demonstrates how to query checkbox, text field, and slider values from the UI, and includes a run() function pattern for managing the UI lifecycle.

Key Concepts

  • Loading .ui files with QUiLoader - Load Qt Designer layouts at runtime using PySide2
  • Signal-slot connections - Wire button clicks to Python callback methods
  • UI value queries - Read checkboxes, text fields, and slider values from widgets
  • QDialog lifecycle - Use a run() function to close existing instances before creating new ones
  • Maya window parenting - Parent Qt dialogs to the main Maya window via OpenMayaUI
Note

This session uses a companion template_ui.ui file created in Qt Designer. The .ui file defines the visual layout (checkbox, text field, slider, and button).

Source Code - template_ui.py

"""
#############################################################################
filename    template_ui.py
author      [author]
course      [course]
Brief Description:
    Qt Template UI
    To be used in conjunction with "template_ui.ui" - place them next to each other
    Session 12A - Mar 31 2020
#############################################################################
"""

import pymel.core as pm
import os

from PySide2 import QtCore
from PySide2 import QtWidgets
from PySide2 import QtUiTools

from shiboken2 import wrapInstance

import maya.OpenMayaUI as omui

def get_maya_window():
    """Return the main Maya window
    """
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(long(main_window_ptr), QtWidgets.QWidget)

def get_script_dir():
    """Returns the directory where the current script lives
    """
    script_file = os.path.abspath(__file__)
    return os.path.dirname(script_file)

class TemplateUI(QtWidgets.QDialog):

    def __init__(self, parent=get_maya_window()):
        # Run the initialization on the inherited QDialog class
        super(TemplateUI, self).__init__(parent)

        # Set the window title
        self.setWindowTitle('Shape Creator')

        # Assemble the file path for the ui file
        ui_file_path = os.path.join(get_script_dir(), 'template_ui.ui')

        # Creat a QFile object form the file path
        qfile_object = QtCore.QFile(ui_file_path)

        # Open the QFile object
        qfile_object.open(QtCore.QFile.ReadOnly)

        # Create a QUI Loader
        loader = QtUiTools.QUiLoader()

        # Load the file as save it to a property
        self.ui = loader.load(qfile_object, parentWidget=self)

        self.ui.btnCreateShape.clicked.connect(self.print_values)

        # Close the file handle
        qfile_object.close()

        # Show the UI
        self.show()

    def print_values(self):
        """Sample method that gets triggered from the button
        All we do here is print some of the value from the UI
        """
        # Get the values from the UI
        checkbox = self.ui.chkTestCheckbox.isChecked()
        text = self.ui.txtTestText.text()
        number = int(self.ui.sldTestSlider.value())

        # Print the values out to the script editor
        print ('CheckBox = %s  Text = "%s"  Number = %i' %(checkbox, text, number))

def run():
    """Checks to see if the UI exists, and closes it
    """
    # Run through every qt widget active inside Maya
    for ui_item in QtWidgets.qApp.allWidgets():
        # If we find a widget whose name matches our class
        if type(ui_item).__name__ == 'TemplateUI':
            # Close it
            ui_item.close()
    # Finally, always create an instance of the UI
    TemplateUI()
← Prev Next ->