maya Creating Maya UI Callback functions


Many widgets include events which can fire callback functions when the user interacts with the widget. For example when a button is pressed, a checkbox checked, or a dropdown chosen you can fire a function.

The exact flag which is associated with these event depends on the widget, but a typical callback would look like this:

 def callback_fn(_ignore):
     print "button pressed"

 button = cmds.button(label='press me', command = callback_fn)

Pressing the button will print "button pressed" to the listener window. Most widget's fire some arguments when their callbacks activate -- the button for example always includes a boolean value -- so you'll need to make sure that the callback handler has the right signature to go with the widget you're using. That's why callback_fn() takes an argument even though it doesn't need it.

Callback Assignment

Maya supports two different ways of attaching callback functions:

   # this works, but is not a great idea
   cmds.button(label = 'string reference', command = 'string_name_of_function')
   # use this form whenever possible
   cmds.button(label = 'direct function reference', command = callback_fn)

In the first example the callback is assigned by a string value. Maya will find the callback in the global Python scope -- which is usually hard to access when writing properly organized code. String-name callbacks are also slower to resolve. The second example passes the actual Python function to the callback -- this form is preferred because it is faster and, if you've failed to provide a valid function to the callback function, you'll know when the UI is created instead of when the UI widgets are actually used.

If you want to pass a argument value to a call back function, you can use a lambda, a closure or a functools.partial bind arguments to the callback.

Using partial:

 from functools import partial
 def callback_fn(myValue, _ignore):  # _ignore swallows the original button argument
     print myValue

 button = cmds.button(label='press me', command = partial(callback_fn, "fooo"))

Using lambda:

 def callback_fn(myValue):
     print myValue

 button = cmds.button(label='press me', command = lambda _ignore: callback_fn("fooo"))
 # here the lambda needs to handle the button argument

Using Closures

b = cmds.button(label = 'press me')
# by defining this function when `b` exists, we can use it later
# without storing it explicitly
def get_button_label(*_):
    print "label of button", b, " is ", cmds.button(b, q=True, l=True)
cmds.button(b, e=True, c=get_button_label)

There' more about string callback names vs. callback function here