Monday, 8 June 2015

Python snippets (Maya) for the budding TD Part 3

I'm continuing my ongoing collection of tips for working in Maya using Python, with a few more small snippets of knowledge that may be of interest...  As per the last article, I've got a few small bites for working with Maya UI's along with some others.

This article is a little shorter as well, but obviously I'll post more at a later date...



A little more UI fun - reading child controls en masse

Part of the process when developing tools and scripts is discovery based on necessity.  In this example, a student had asked about how to read a large set of checkbox controls from within a frame layout and make use of them.

Now, one way would be to assign a unique variable to each one.  That could be in the guise of a list, dictionary or unique name - which we discussed the creation of in the previous article.  However when there are a LOT of identical control types, this approach is somewhat messy.

Another approach would be to iterate through the controls and retrieve their information directly without needing any variables to reference them.  When there are a lot of identical control options offered on a form, this would make much more sense.

It comes down to hierarchy - again...

As I discussed in the previous article, Maya's UI works as a hierarchy - with individual Layouts becoming parent containers that house child controls (and other layouts) within them.  We can query a layout for a list of its children using the parameter childArray (ca).  This returns a list of the control names which make it easy for us to retrieve their information without having to query a variable.

In this example I've created a series of checkboxes to demonstrate this process.  The only thing that may not be obvious in here is that in your function, you will need to recreate the proper full path to the checkbox controls by adding the layout and control name back together with a pipe ( | ) delimiter.

import maya.cmds as cmds

# Define a function that queries the checkboxes and displays
# information about them in the history panel.
def getCheckboxes( *args ):

    # Ask for a list of controls inside the ckBoxLayout
    childList = cmds.columnLayout( cBoxLayout, q=True, ca=True)

    # Look through the list of child controls
    for eachOne in childList:
        # Create the path to the control.
        ctrlID = cBoxLayout + "|" + eachOne
        print "\nCheckbox contains:"
        print "Label: %s" % cmds.checkBox(ctrlID,q=True, l=True)
        print "State: %s" % cmds.checkBox(ctrlID,q=True,v=True )


# Create a Window
cmds.window(t='Checkboxes galore')

# Create a Layout
cmds.columnLayout()
cmds.text(l="\nLook at all these lovely check boxes\n")

# Create a new child Layout for the checkboxes
cBoxLayout = cmds.columnLayout()

# Add a control here places it under ckBoxLayout
cmds.checkBox(l='check box one')
cmds.checkBox(l='check box two')
cmds.checkBox(l='check box three')
cmds.checkBox(l='check box four')
cmds.setParent('..')

# Add a button that displays the details of the checkboxes
cmds.button(l='Query checkboxes', command='getCheckboxes()')

# Show the Window
cmds.showWindow()


A pack of mixed nuts - eh, I mean controls...

What if there are a variety of different controls available in a Layout?  Luckily the control's name from the childArray will include its type, and a value based on how many controls have been generated.  This type can also be queried by simply stripping the numeric value from the end of the control name.  I've used a list mapping function to keep all non-numeric characters which cleans it up nicely.

import maya.cmds as cmds

# Define a function that queries the checkboxes and displays
# information about them in the history panel.
def getCheckboxes( *args ):

    # Ask for a list of controls inside the mainLayout
    childList = cmds.columnLayout( mainLayout, q=True, ca=True)

    # Look through the list of child controls
    for eachOne in childList:

        # Strip out the numeric characters using list mapping
        # and using .join to combine the list into a new string
        print ''.join(ch for ch in eachOne if not ch.isdigit() )

# Create a Window
cmds.window(t='Checkboxes galore')

# Create a Layout with various controls
mainLayout = cmds.columnLayout()
cmds.text(l="\nHello - look at all these lovely check boxes\n")
cmds.checkBox(l='check box one')
cmds.checkBox(l='check box two')
cmds.button(l='Print ctrls', command='getCheckboxes()')

# Show the Window
cmds.showWindow()



This second approach allows for a lot more flexibility with more complex control set ups.  Using a simple if to test the control type, or even using the control type to define the python request itself (using exec) like below gives us less code.

Note to keep the example simple, I've queried exists (ex) as this is found in every control type...  Not all controls obviously return the same fields so some checking would be needed here.


import maya.cmds as cmds

# Define a function that queries the checkboxes and displays
# information about them in the history panel.
def getCheckboxes( *args ):

    # Ask for a list of controls inside the mainLayout
    childList = cmds.columnLayout( cBoxLayout, q=True, ca=True)

    # Look through the list of child controls
    for eachOne in childList:

        # Create the path to the control.
        ctrlID = cBoxLayout + "|" + eachOne

        # Strip out the numeric characters using list mapping
        # and using .join to combine the list into a new string
        ctrlType = ''.join(c for c in eachOne if not c.isdigit() )

        # Use the control type to query it. Just ask for value
        print "Control Name : %s" % eachOne
        print "Type was : %s" % ctrlType

        # Get the value
        exec('ctrlVal = cmds.'+ctrlType+'(ctrlID,q=True,ex=True)')
        print "Exists : %s" % ctrlVal

# Create a Window
cmds.window(t='Checkboxes galore')

# Create a Layout with various controls
cBoxLayout = cmds.columnLayout()
cmds.text(l="\nHello - look at all these lovely check boxes\n")
cmds.checkBox(l='check box one')
cmds.checkBox(l='check box two')
cmds.button(l='Print ctrls', command='getCheckboxes()')

# Show the Window
cmds.showWindow()


Mix-n-matching between Python and MEL

Occasionally you're going to get something where you will need to mix one of Maya's scripting languages with another.   As a simple example, lets take this particular MEL command to display a confirmation dialog (not that we would given that there is a python equivalent of the same command ;) )

confirmDialog -t "testing" -m "this is a test" -b "exit"

To call this from within a Python script, we need to import the maya.mel module.  This module has a function called eval() - not to be mistaken with the general eval() function - that will evaluate and execute our MEL as shown below.

import maya.mel as mm
mm.eval('confirmDialog -t "testing" -m "this is a test" -b "exit"')

If you find you need to mix in various quote characters inside strings, then don't forget we can escape them with a back slash if necessary.  However while commands that exist in MEL will usually have a Python version, its things such as adding nCloth to a mesh that calls a custom MEL script in Maya (doCreateNCloth.mel) to do its job.

import maya.mel as mm
mm.eval('doCreateNCloth 0')

That's about it (again)

Just a little shorter then the last 2-3 articles - more with a few tips for UI then anything else - but I felt while this stuff is fresh in my mind, I'd get it on the blog and hopefully its given you a few more things that are useful in your development of scripts and tools.

As always, I'll keep posting up things as I work through them.  Thanks for reading...

0 comments:

Post a Comment