Question

I'm busy creating a function in my rigging tool which allows mirroring of joints and replacing the prefix. The mirroring of joints (both behaviours and orientation) is working but I get an error when I search and replace what is in my two text fields. The prefix of joints in the scene is either R_ or L_ and I would like to replace them with this.

The error is as follows: NameError: name searchFor is not defined. The odd part here is that I actually create a variable called searchFor and one called replaceWith. See the code below:

import maya.cmds as cmds 

child2 = cmds.gridLayout( cw = self.size[ 0 ] / 2 - 10, nc = 2 )
cmds.text( l = ' Mirror Joints', al = 'left', font = "boldLabelFont" ) 
cmds.separator( style = 'none' )
searchFor = cmds.textFieldGrp( tx = 'Search for...' )
replaceWith = cmds.textFieldGrp( tx = 'Replace with...' )  

cmds.button( label = 'Mirror Orientation',
             command = "cmds.mirrorJoint( cmds.ls( sl = True ), 
             mirrorYZ = True, 
             mirrorBehavior = False, 
             searchReplace = cmds.textFieldGrp( searchFor, q = True, tx = True),
             cmds.textFieldGrp( replaceWith, q = True, tx = True )" ) 

cmds.button( label = 'Mirror Behaviour',
             command = "cmds.mirrorJoint( cmds.ls ( sl = True ), 
             mirrorYZ = True, 
             mirrorBehavior = True )" ) 

The code is part of the UI as where the other functions are called forth from another module. Can it be that I need to create a function which includes the mirrorJoint command in the UI module? Or is this a viable approach?

For a better view of the code: https://dl.dropboxusercontent.com/u/545575/python.zip

Was it helpful?

Solution

You're using a string to call the function, and that string gets interpreted in the global scope - as if you'd typed it in the listener; outside the body of your function, 'searchFor' does not exist.

Here's a reference on how maya sees callback commands: http://techartsurvival.blogspot.com/2014/04/maya-callbacks-cheat-sheet.html

MHLester's example will do what you want, you will have to watch out for closures. The lambda will inherit variables from the scope where it is defined -- but at the time the scope closes, not at the time it was defined; this might cause some surprises. For example if you tried this:

def test():
    w = cmds.window()
    cmds.columnLayout()    
    example = 1
    cmds.button("test", c= lambda *_:  sys.stdout.write( "example: %i" % example ) )
    example = 4
    cmds.showWindow(w)

clicking the button will print '4', even though it looks like it should be '1'.

OTHER TIPS

Yes, you need a function. Making the command a string only works if all objects referenced are in global space (which is discouraged, so by extension string commands are also discouraged)

The easiest way to make a function is to use a lambda:

cmds.button(   
    label='Mirror Orientation',
    command=lambda *_: cmds.mirrorJoint(cmds.ls (sl=True), mirrorYZ=True, mirrorBehavior=False, searchReplace=(cmds.textFieldGrp(searchFor, q=True, tx=True),cmds.textFieldGrp(replaceWith, q=True, tx=True)))
)

Lambda makes an unnamed function, and the *_ allows for any number of throwaway arguments. When called, it in turn calls the cmds.mirrorJoint that was previously in the string command.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top