Its been awhile since I posted. Ive been creating a lot of Python UI’s of late. I have seen others struggle with creating their first UI. There are a few gotchas and the best way to set up a Python UI is different than setting it up with MEL.
A good way to setup your UI is to encapsulate the UI in a class including the functions you will use with the UI. You dont need all of your functions inside of the class. If you need to work with a function that is external to the class, you can use a partial function. When you set a button command to use a function it is best not to give it a string like you would in MEL. You should pass the functions directly to the command. You should not pass the functions as if you called them however like function() but by just giving it the name. If you need to pass an argument you need to use a partial function so the function does not get called until the user presses the UI item. You should note the UI button command happens to always pass one argument even if you dont pass anything to the function. If you pass your function one argument it will receive two, or if you pass two it will receive three. This is easily remedied by adding an extra unused argument.
I have several personal projects taking up my time right now so I am going to be brief on the how to and what does what part. The following example should help you get started. You can execute it from the script editor and start playing around with it.
import maya.cmds as cmds
from functools import partial
def myfunc(inst=None, thing=None, arg=None):
print 'arg: ', arg
print 'inst: ', inst
print 'thing: ', thing
data = cmds.button(inst.btnA, query=True, label=True)
print data
class ui():
def __init__(self, winName="winTheWindow"):
self.winTitle = "The Window"
self.winName = winName
def create(self):
if cmds.window(self.winName, exists=True):
cmds.deleteUI(self.winName)
cmds.window(self.winName, title=self.winTitle)
self.mainCol = cmds.columnLayout( adjustableColumn=True )
self.btnA = cmds.button( label='Press Me - External Func', c=partial(myfunc, self, 'say...') )
self.btnB = cmds.button( label='Press Me - Internal Func', c=partial(self.a, 'something...') )
self.btnC = cmds.button( label='Press Me - Internal Func No Args', c=self.b)
cmds.showWindow( self.winName )
cmds.window(self.winName, edit=True, widthHeight=[250,75])
def a(self, myarg=None, arg=None):
print 'myarg: ', myarg
def b(self, arg=None):
print 'buttons require an argument'
print 'the argument passed in will always be the last argument'
# create the window
inst = ui()
inst.create()
Have fun,
Ryan
February 4th, 2010 at 12:56 pm
This is some good stuff! partial() is new to me but I gave it a try and found that it has the same problems that lambda, where each action is placed on the undo queue individually. The only way I know to place the command on the undo queue correctly is with a string command.
# begin code
import maya.cmds as cmds
from functools import partial
def proxy( inst=None ):
lameness( count=3 )
def lameness( inst=None, count=1 ):
for i in range(count):
polyCube()
move( 3*i,0,0 )
def starArgs( *args ):
for i in range(5):
polySphere()
move( 3*i,0,0 )
cmds.window()
cmds.columnLayout()
cmds.button( l=’Lambda Undo fail’, c=lambda *args: lameness(count=3) )
cmds.button( l=’Partial() Undo fail’, c=partial( lameness, count=3 ) )
# Only method that undoes in one action!
cmds.button( l=’String Undo *success*’, c=’lameness(count=3)’ )
cmds.button( l=’Star args fail’, c=starArgs )
cmds.button( l=’Proxy Lambda Undo fail’, c=lambda *args: proxy() )
cmds.button( l=’Proxy Partial() Undo fail’, c=partial( proxy ) )
cmds.showWindow()
# Calling via script editor and undoing works correctly
lameness( count=3 )
# end code
Any ideas on dealing with this? All I’ve come up with are hacky and not pretty.
February 4th, 2010 at 11:40 pm
I tried running the following code on 2008, 2009, and 2010 and they all failed to do as I expected:
import maya.cmds as cmds
from functools import partial
def odd( inst=None, count=1 ):
for i in range(count):
cmds.polyCube()
cmds.move( 3*i,0,0 )
cmds.window()
cmds.columnLayout()
cmds.button( l=’Partial() Undo fail’, c=partial( odd, count=3 ) )
cmds.showWindow()
# works
odd( count=3 )