Add to UI when button is pressed

I’m attempting to create a UI after pressing a button, will ask for a name. after the user enters a name it creates a Dropdown box with a set of 3 textfieldbuttongroups in one tab and a set of 4 buttons in another. I eventually want to be able to add and remove them.

Ive tested the dropdown and the set of buttons and those work well, but when it comes to adding these to my main UI, I’ve gotten as far as getting a text dialog to ask for a name. Actually adding to the UI has been really confusing to me. I created a class for the UI elements(Widgets?) I want to add and wanted to call the class after the user enters the name but I’ve sort of hit a wall. Was hoping someone could point me in the right direction.

UI Code here:

import maya.cmds as cmds
import pymel.core as pm
import maya.cmds as cmds
import maya.OpenMaya as om
import math
 
from functools import partial


###################################################################################
            #TOOL WINDOW#                       #TOOL WINDOW#
###################################################################################
def frameCollapseChanged(ToolWindow):
         cmds.evalDeferred("cmds.window('ToolUI', e=1, h=sum([eval('cmds.' + cmds.objectTypeUI(child) + '(\\'' + child + '\\', q=1, h=1)') for child in mc.columnLayout('" + ToolWindow + "', q=1, ca=1)]))")
 
     #check to see if window exists
if cmds.window("ToolUI", exists = True):
     cmds.deleteUI("ToolUI")
     #create window
ToolWindow = cmds.window("ToolUI", title = "Tool UI", mnb = True, mxb = False,)
    #create a main layout
mainLayout = cmds.columnLayout (adjustableColumn=True)

form = cmds.formLayout()
tabs = cmds.tabLayout(innerMarginWidth=5, innerMarginHeight=5,cr=True)
cmds.formLayout( form, edit=True, attachForm=((tabs, 'top', 0), (tabs, 'left', 0), (tabs, 'bottom', 0), (tabs, 'right', 0)) )
###################################################################################
            #SETUP TAB CONTENT#                       #SETUP TAB CONTENT#
###################################################################################
child1 = cmds.rowColumnLayout(numberOfColumns=1,adjustableColumn=True)
cmds.text(label = 'Root Joint Selection', align ='center')
cmds.button(label = 'Add Selector', command=lambda event:Name_DialogBox())

cmds.setParent( '..' )

###################################################################################
            #TOOL TAB CONTENT#                       #TOOL TAB CONTENT#
###################################################################################

child2 = cmds.rowColumnLayout(numberOfColumns=2, columnWidth=(300,250),adjustableColumn=True)

cmds.columnLayout(columnAttach=('both', 5),columnWidth=300, columnAlign="center", adjustableColumn=True )
cmds.text(label = 'FK IK Switch', align ='center')



cmds.setParent( '..' )
cmds.setParent( '..' )

###################################################################################
            #TOOL TABS#                                #TOOL TABS#
###################################################################################
cmds.tabLayout( tabs, edit=True, tabLabel=((child1, 'Set Up'), (child2, 'Tool')) )

cmds.showWindow()

 
winHeight = 0
     # iterate through all children of the main layout
for child in cmds.columnLayout(mainLayout, q=1, ca=1):
         # for each child, get it's type, then use that run an eval command to get that ui item's 
         #height and add it to the height variable
     winHeight += eval('cmds.' + cmds.objectTypeUI(child) + '("' + child + '", q=1, h=1)')
     # set the window height with the gathered height values
cmds.window('ToolUI', e=1, h=winHeight) 


#################################################################################################################
            #CREATE SELECTION LISTS#                                #CREATE SELECTION LISTS# 
#################################################################################################################

def Name_DialogBox():
    result = cmds.promptDialog(
            title='Rename Object',
            message='Enter Name:',
            button=['OK', 'Cancel'],
            defaultButton='OK',
            cancelButton='Cancel',
            dismissString='Cancel')

    if result == 'OK':
        InstanceName = cmds.promptDialog(query=True, text=True)
        print InstanceName
        ###Create New Tab using text as name####
        New_Tab_Set(InstanceName)
        return InstanceName




class New_Tab_Set:
    
    def __init__(self, InstanceName):
        self.name = InstanceName
            
    
    def Set_up_Tab(self):
        
        self.tab1=cmds.frameLayout (width = 300, label = self.name,  collapse = True, collapsable = True, marginWidth = 5, parent = child1);
        self.cmds.text(label = self.name, align ='center')
        self.tsL0 =cmds.textFieldButtonGrp(ed=False, adj=1,cal=(1,"left"),cw3=(10,100,25), cl3=("left","left","left") , 
                                    buttonLabel='Root   FK',bc = 'Create_Selection_Chains.select_joints_afk(left_arm_select)' )
        self.gtF0 = tsL0 

        self.tsL1 = cmds.textFieldButtonGrp(ed=False, adj=1,cal=(1,"left"),cw3=(10,100,25), cl3=("left","left","left") , 
                                    buttonLabel='Wrist   IK',bc = 'Create_Selection_Chains.select_joints_aikw(left_arm_select)')
        self.gtF1 = tsL1

        self.tsL2 = cmds.textFieldButtonGrp(ed=False, adj=1,cal=(1,"left"),cw3=(10,100,25), cl3=("left","left","left") , 
                                    buttonLabel='Elbow IK',bc = 'Create_Selection_Chains.select_joints_ikpv(left_arm_select)' )
        self.gtF2 = tsL2

        self.cmds.separator(h=5)
        self.cmds.button(label= 'Remove' + self.name, command = 'Remove()', width=100)
        self.cmds.separator(h=5)



    def Tool_Tab(self):

        self.cmds.columnLayout(columnAttach=('both', 5),columnWidth=300, columnAlign="center", adjustableColumn=True )
        self.cmds.text(label = 'FK IK Switch', align ='center')
        self.cmds.separator(h=5)
        ###################################################################################
        #Left Arm                                               #Left Arm
        self.cmds.text(label = 'Left Arm', align ='center')
        self.cmds.separator(h=5, style = 'none')
        self.cmds.rowLayout(numberOfColumns=2, columnWidth2=(190, 100))
        ###################################################################################
        # Left Arm IK FK Switch                                 # Left Arm IK FK Switch
        self.cmds.button(label='IK', command = 'IKswitch()', width=100)
        self.cmds.button(label='FK', command = 'FKswitch()', width=100)
        self.cmds.setParent('..')
        self.cmds.rowLayout(numberOfColumns=2, columnWidth2=(190, 100))
        ###################################################################################
        # Left Arm IK FK Snapping                               # Left Arm IK FK Snapping
        self.cmds.button(label='FK 2 IK', command = 'Create_Selection_Chains.fk_2_ik(left_arm_select)', width=100)
        self.cmds.button(label='IK 2 FK', command = 'Create_Selection_Chains.ik_2_fk(left_arm_select)', width=100)
        self.cmds.setParent('..')
        self.cmds.separator(h=5, style = 'none')
        self.cmds.separator(h=5)

        

Have you thought about using PySide2 or QT for ui stuff? I found it heaps easier to use etc

1 Like

I had considered it, but I managed to figure this out. Plus I’d like to understand how this works a little more before trying PySide2 or QT

It might be a good idea to wait on going full OOP while you get used to the way maya.cmds handles GUI. It’s actually quite simple conceptually but it tends to lead to spaghetti code until you break it down.

Here’s a super-minimal example of how to dynamically add and remove widgets based on user input. The only real ‘trick’ is to hang on to references to the original items so they are easy to add to or remove. You can always “add” to a layout by using cmds.setParent – anything you create will be appended to the last thing you setParented to. So with some extra layouts as placeholders its pretty easy to add to an existing layout

def dynamic_window():
    window = cmds.window()
    main = cmds.columnLayout(width=512)
    row = cmds.rowLayout(nc=2, cw2 = (384, 128))
    entry = cmds.textField(width=384)
    btn = cmds.button(label = 'set', width=128)
    
    # add a layout to hold the dynamic stuff
    cmds.setParent(main)
    dynamic = cmds.columnLayout(width=512)
    cmds.text(label='I get replaced')
    
    
    def rebuild(*_):
        new_name = cmds.textField(entry, q=True, text=True)
        segments = new_name.split()
        if not new_name:
            cmds.warning("enter a name")
            return
        
        delenda = cmds.layout(dynamic, q=True, childArray=True)
        cmds.deleteUI(delenda)
        cmds.setParent(dynamic)
        
        new_menu = cmds.optionMenu(label='dynamic menu')
        for name in segments:
            cmds.menuItem(label = name)
            
        # dummy function to do something with the inpuyt
        def menu_callback(selected):
            print "you selected", selected
        
        cmds.optionMenu(new_menu, e=True, cc = menu_callback) 
            
    # now attach the rebuild function to the button
    cmds.button(btn, e=True, c=rebuild)
    cmds.showWindow(window)

dynamic_window()

Run it and type a space delimited list of menu items into the text bar; the button will make a menu out of them and add it to the window.

You might find this blog post a useful reference for the various ways of hooking things up. Nowadays I’m almost all closures all the time, it’s a bit of a change from typical OOP but it’s usually a lot less boilerplate. However the technique works with any programming style: just delete the contents of your placeholder layout, setParent to it, and add new controls.

4 Likes