Here's an excerpt from pymel's documentation
<http://pymel.googlecode.com/svn/docs/toc-pymel.core.windows-module.html>
regarding
this issue. It applies whether or not you actually use pymel to create your
gui:
Command Callbacks
One common point of confusion when building UIs with python is command
callbacks. There are several different ways to handle command callbacks on
user interface widgets.
Function Name as String
The simplest method of setting up a callback is to pass the name of the
callback function as a string. Maya will try to execute this as a python
function. Here's a simple example:
from pymel import *
def buttonPressed(arg):
print "pressed!"
win = window(title="My Window")
layout = columnLayout()
btn = button( command='buttonPressed' )
showWindow()
This example works fine if you run it from the script editor, but if you
save it into a module, say myModule, and then import that module as normal (
e.g. import myModule ), it will cease to work (assuming you haven't already
run it from the script edtior). This is because the *namespace* of the
function has changed. It can no longer be found as buttonPressed, because
from Maya's perspective, its new location is myModule.buttonPressed.
There are several solutions to this. First, you can import the contents of
myModule directly into the main namespace ( e.g. from myModule import * ).
This will allow buttonPressed to be accessed without the namespace.
Alterately, you can change your script and prefix the function with the
module it will be imported from:
button( command="myModule.buttonPressed" )
The problem with both of these solutions is that you must ensure that the
module is *always* imported the same way, and, if you plan to share your
module with someone, it's pretty impossible to do this.
A more robust solution is to include an import command in the string to
execute.
button ( command="import myModule; myModule.buttonPressed" )
Another major limitation with this method is that it is hard to pass
parameters to these functions since these have to be converted into a string
representation. This becomes impractical when the parameters are complex
objects, such as dictionaries, lists, or other custom objects.
So, as simple as the string method may seem at first, it's can actually be
quite a pain. Because of these limitations, this method is not recommended.
Function Object
When using this method, you pass an actual function object (without the
parentheses). The callback function has to be defined before it is passed to
the command flag.
from pymel import *
def buttonPressed(arg):
print "pressed!"
win = window(title="My Window")
layout = columnLayout()
btn = button( command=buttonPressed )
showWindow()
The difference from the previous example is subtle: buttonPressed does not
have quotes around it, meaning it is not a string.
This method is very robust, its primary weakness lies in passing arguments
to our function.
In the above example, we defined our callback function like this:
def buttonPressed(arg):
print "pressed!"
Notice that the function has one argument: arg. We had to include this
argument in our callback function because the
button<http://pymel.googlecode.com/svn/docs/pymel.core.windows-module.html#button>
UI
widget, like many others, automatically passes arguments to your function,
whether you want them or not (These forced arguments allow python in Maya to
mimic the "myCommand #1" functionality in MEL). If we had defined our
function like this...
def buttonPressed():
print "pressed!"
...when we pressed our button we would have gotten this error:
# TypeError: buttonPressed() takes no arguments (1 given) #
In our case, the arguments passed by the button are actually pretty useless,
but sometimes they contain the state of the UI element, such as whether a
checkbox is on or off. The tricky part is that different UI elements pass
differing numbers of arguments to their callbacks, and some pass none at
all. This is why it is best for your command to use the *args syntax, like
so:
def buttonPressed(*args):
print "pressed!"
The asterisk in front of args allows it to accept any quantity of passed
arguments. Making it a habit to use this syntax for your callbacks can save
you a lot of headache.
Now, what if I want to pass a different argument to my function besides
those automatically sent by the UI element, or what if I'm using a function
that someone else wrote and I can't add the *args to it? Fear not, there is
a solution...
Lambda Functions
Combining lambda functions with the lessons we learned above adds more
versatility to command callbacks. You can choose exactly which args you want
to pass along.
from pymel import *
def buttonPressed(name):
print "pressed %s!" % name
win = window(title="My Window")
layout = columnLayout()
name = 'chad'
btn = button( command = lambda *args: buttonPressed(name) )
showWindow()
So, what exactly is a lambda? It's a special way of creating a function on
one line. It's usually used when you need a function but you don't need to
refer to it later by name.
In the above example, this portion of the code...
name = 'chad'
btn = button( command = lambda *args: buttonPressed(name) )
...could have been written as:
name = 'chad'def tempFunc(*args):
return buttonPressed(name)
btn = button( command = tempFunc )
The lambda is just a shorthand syntax that allows us to do it on one line.
The point of the lambda is to put a function in before of the callback that
does the real work so that we can control what arguments will be passed to
it.
This method, too, has a drawback. It fails when used in a 'for' loop. In the
following example, we're going to make several buttons. Our intention is
that each one will print a different name, but as you will soon see, we
won't succeed.
from pymel import *
def buttonPressed(name):
print "pressed %s!" % name
win = window(title="My Window")
layout = columnLayout()
names = [ 'chad', 'robert', 'james' ]for character in names:
button( label=name, command = lambda *args: buttonPressed(character) )
showWindow()
When pressed, all the buttons will print 'james'. Why is this? Think of a
lambda as a "live" or dynamic object. It lives there waiting to execute the
code it has been given, but the variables in that code are live too, so the
value of the variable named character changes with each iteration through
the loop, thereby changing the code that lambda is waiting to execute. What
is its value at the end of the loop? It's 'james'. So all the lambda's
execute:
buttonPressed('james')
To solve this we need to "pin" down the value of our variable to keep it
from changing. To do this, pymel provides a
Callback<http://pymel.googlecode.com/svn/docs/pymel.core.windows.Callback-class.html>
object...
Callback Objects
In my experience this method handles all cases reliably and predictably, and
solves the 'lambda' issue described above. A
Callback<http://pymel.googlecode.com/svn/docs/pymel.core.windows.Callback-class.html>
object
is an object that behaves like a function, meaning it can be 'called' like a
regular function. The Callback object 'wraps' another function, and also
stores the parameters to pass to that function. Here's an example:
from pymel import *
def buttonPressed(name):
print "pressed %s!" % name
win = window(title="My Window")
layout = columnLayout()
names = [ 'chad', 'robert', 'james' ]for character in names:
button( label=name, command = Callback( buttonPressed, character )
showWindow()
Our example now works as intended. The
Callback<http://pymel.googlecode.com/svn/docs/pymel.core.windows.Callback-class.html>
class
provides the magic that makes it work. Pay close attention to how the
Callback is created: first parameter is the function to wrap, the
buttonPressed function, and the rest are parameters to that function, in our
case character. The Callback stores the function and its arguments and then
combines them when it is called by the UI element. The
Callback<http://pymel.googlecode.com/svn/docs/pymel.core.windows.Callback-class.html>
class
ignores any arguments passed in from the UI element, so you don't have to
design your function to take these into account. However, if you do want
these, use the alternate callback object
CallbackWithArgs<http://pymel.googlecode.com/svn/docs/pymel.core.windows.CallbackWithArgs-class.html>:
the additional arguments will be added to the end of yours.
2009/2/12 Francis Vega Castillo <[email protected]>
> Hi kurian :)
>
> Thanks, now works :P, anyway I think i'll change the way to work with Maya
> UI querying ui values...
>
> Francis.
>
>
> 2009/2/12 kurian os ™ (R)കോപ്പിയടിച്ചാല്(c)ഗോതമ്പുണ്ട! <[email protected]>
>
>> sorryyyyyy .. i pasted wrong one check this
>>
>> *import maya.cmds as cmds
>> class foo():
>> def __init__(self):
>>
>> if cmds.window("ventana", exists=1):
>> cmds.deleteUI("ventana", window=1)
>>
>> cmds.window('ventana')
>> cmds.columnLayout('colLayout')
>> cmds.button('boton', c=lambda event:self.printAnything("Hi
>> python"))
>> cmds.showWindow('ventana')
>>
>> def printAnything(self,thing):
>> print thing
>>
>> f = foo()
>> *
>>
>>
>>
>> 2009/2/12 kurian os ™ (R)കോപ്പിയടിച്ചാല്(c)ഗോതമ്പുണ്ട! <[email protected]>
>>
>> Looking for this ??
>>>
>>>
>>> *import maya.cmds as cmds
>>>
>>> class foo(object):
>>> def __init__(self):
>>>
>>> if cmds.window("ventana", exists=1):
>>> cmds.deleteUI("ventana", window=1)
>>>
>>> cmds.window('ventana')
>>> cmds.columnLayout('colLayout')
>>> cmds.button('boton', c=self.printAnything("Hi python"))
>>> cmds.showWindow('ventana')
>>>
>>> def **printAnything**(self, **thing**):
>>> print thing
>>>
>>> f = foo()*
>>>
>>> On Thu, Feb 12, 2009 at 8:18 AM, Francis Vega Castillo <
>>> [email protected]> wrote:
>>>
>>>> Hi all!
>>>> I've got this code and it doesnt works. I can't pass args from button
>>>> command to printAnything function :S.
>>>> what am I doing wrong?
>>>>
>>>> Thanks!
>>>> ---
>>>>
>>>> *import maya.cmds as cmds
>>>>
>>>> class foo(object):
>>>> def __init__(self):
>>>>
>>>> if cmds.window("ventana", exists=1):
>>>> cmds.deleteUI("ventana", window=1)
>>>>
>>>> cmds.window('ventana')
>>>> cmds.columnLayout('colLayout')
>>>> cmds.button('boton', c=self.printAnything("Hi python"))
>>>> cmds.showWindow('ventana')
>>>>
>>>> def **printAnything**(self, **thing**):
>>>> print thing
>>>>
>>>> f = foo()*
>>>>
>>>> ---
>>>>
>>>>
>>>>
>>>
>>>
>>> --
>>> സ്നേഹിക്കയില്ല ഞാന്
>>> നോവുമാത്മാവിനെ സ്നേഹിച്ചിടാത്തൊരു
>>> തത്വശാസ്ത്രത്തെയും
>>>
>>
>>
>>
>> --
>> സ്നേഹിക്കയില്ല ഞാന്
>> നോവുമാത്മാവിനെ സ്നേഹിച്ചിടാത്തൊരു
>> തത്വശാസ്ത്രത്തെയും
>>
>>
>>
>
> >
>
--
- Ofer
www.mrbroken.com
--~--~---------~--~----~------------~-------~--~----~
Yours,
Maya-Python Club Team.
-~----------~----~----~----~------~----~------~--~---