Maya Python UI

A lot of people ask me how to deal with UI’s in Maya, especially how to lay things out properly. The example below shows a simple way to construct a ui in Python. One thing that’s nice about using Python for ELF UI’s is how UI names can be easily unique and accessible. In MEL, I got used to making UI names as specific as possible, and often times concatenating strings together to represent things like this:

string $mybutton = `button -label "test" ("myButton_" + $name)`;

Then if you want to access it, you need to know $name and call this:

button -q ... ("myButton_" + $name);

This is completely fine and manageable, but now with Python, it’s more clear to do something like this:

self.myButton = cmds.button(label='test')

Then anytime you want to access it in Python, you can just call:

cmds.button(self.myButton, q=True, ...)

The other thing that can be great is to store UI elements in lists in Python. So if you want to create a layout that has a textField and two buttons for every object that’s selected, you could iterate through your selection, appending a new layout to your list for each object.

For example:

def createMyLayout( obj, parent ):
    cmds.setParent(parent)
    c = cmds.columnLayout()
    text = cmds.textField(text=obj)
    button1 = cmds.button(label="one")
    button2 = cmds.button(label="two")
   
    return c

myLayouts = []
w = cmds.window("example", title="Example")
c = cmds.columnLayout()
for selectedObject in cmds.ls(sl=True):
    myLayouts.append(createMyLayout(selectedObject, c))
cmds.showWindow(w)

So this example could be even better if you defined a class, but already, it’s great that there’s a function that generates the layout for each object and then stores it so you could access it later without worrying what Maya actually names it.

Also in this example, I define my function to accept the parameter: ‘parent’. I started this after seeing many of the UI MEL scripts in Maya are setup like that. It also seems to make things more clear in the code, instead of calling “setParent ..” all the time, you’re explicitly telling it which layout to put new things under.

My last example tries to put things together into a Python class. It shows how to access UI elements which are stored as members of the class and how to handle UI control callbacks as well as how to use the formLayout. The formLayout has been my secret to controlling how UI’s are displayed. The great thing about it is you can specify where controls get placed on the layout and how other controls get place around it. It’s also the most consistent way of making controls expand / contract when the window is resized. So if you want a button to be attached to the left / right side of the window, you can just use the formLayout’s attachForm option.

You can actually run this, but copy pasting into your Python Script Editor, then you can just type something like:

m = myUI()

This will immediately create the UI because the UI was defined / created in the class’ __init__ method.

The other thing you can do is access members of myUI from the instance: m like this:

cmds.button(m.rename, q=True, label=True)

This will query the label of the rename button that was defined in __init__:

self.rename = cmds.button(label='Rename', w=100, c=self.rename)

Here’s the generic UI code as example:

import maya.cmds as cmds

class myUI:
    def __init__(self):
        self.name = "myUI"
        self.title = "My UI"

        # Begin creating the UI
        if (cmds.window(self.name, q=1, exists=1)): cmds.deleteUI(self.name)
        self.window = cmds.window(self.name, title=self.title)

        self.form = cmds.formLayout()
        self.fromText = cmds.textFieldButtonGrp(label='From: ', buttonLabel='...', bc=self.fromTextLoad)
        self.toText = cmds.textFieldButtonGrp(label='To: ', buttonLabel='...', bc=self.toTextLoad)
        self.rename = cmds.button(label='Rename', w=100, c=self.rename)

        # Attach elements to form
        cmds.formLayout( self.form,
            edit=True,
            attachForm=[
                (self.fromText, 'top', 2),
                (self.fromText, 'left', 2),
                (self.fromText, 'right', 2),
                (self.toText, 'left', 2),
                (self.toText, 'right', 2),
                (self.rename, 'left', 2)
                ],
            attachControl=[
                (self.toText, 'top', 2, self.fromText),
                (self.rename, 'top', 2, self.toText)
            ]
        )

        cmds.window(self.window, e=1, w=430, h=103)
        cmds.showWindow(self.window)

    def fromTextLoad(self, *args):
        print args
        sel = cmds.ls(sl=True)
        if len(sel):
            # Load first selected
            cmds.textFieldButtonGrp(self.fromText, e=True, text=sel[0])
       
    def toTextLoad(self, *args):
        sel = cmds.ls(sl=True)
        if len(sel):
            # Load first selected
            cmds.textFieldButtonGrp(self.toText, e=True, text=sel[0])
       
    def rename(self, *args):
        fromText = cmds.textFieldButtonGrp(self.fromText, q=True, tx=True)
        toText = cmds.textFieldButtonGrp(self.toText, q=True, tx=True)
        print "Rename from: %s to: %s" % (fromText, toText)
This entry was posted in Maya. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. pnut
    Posted March 5, 2010 at 3:40 pm | Permalink

    freakin sweet

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>