[PyMEL] Callbacks and functional arguments

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

Thread Tools Search this Thread Display Modes
Old 04 April 2013   #1
[PyMEL] Callbacks and functional arguments

I encountered a problem recently where I used the PyMEL Callback function. First is the function object 'exportObjects', then two keyword args, one of which calls a function that returns a value into the arg. The problem is that that function gets evaluated right when the button is created, instead of when I push the button, so the return value is set already. How do I delay the function inside the Callback until the button is pressed?

objects = getObjects( mode= buttonInfo[1], scrollListName= scrollListName ), 
scrollListName = scrollListName )

I'll keep working on it, but any vague hint at a solution would be greatly appreciated.

Last edited by RawMeat3000 : 04 April 2013 at 09:32 AM.
Old 04 April 2013   #2
Have a read about 'lambda' and 'functools.partial'.

Old 04 April 2013   #3
I think the only way is to place the getObjects method in your callback method. All command specific actions should be placed in the command.
www.renderwiki.com - www.openmaya.net
Old 04 April 2013   #4
An example of what you could do is here:

from functools import partial

def get_objects(type):
	return pm.selected(type=type)

def exportObjects(objects=None, p=0):
	if objects:
		objects = objects()
	print "objects are", objects, p

# A window to test the menu in...
winX = pm.window( menuBar=True, width=200 )
menuX = pm.menu( label='callBackExample', tearOff=True )
btns = ['btn1', 'btn2']
for i, btn in enumerate(btns):
	pm.menuItem(p=menuX, label = btn,
		c = pm.Callback(exportObjects, objects = partial(get_objects, 'transform'), p=i))

Old 04 April 2013   #5
I figured partial wouldn't work since lambda and Callback both didn't in the same situation, but I think I'll try it. I did some reading and found an easier solution than trying to use PyMEL's Callback and lambda in in the same command. I made an intermediary function that takes any arguments I need from the button and calls both the getObjects function and the export function, instead of having the export function call getObjects in its argument, inside a Callback function.

So all the relevant code looks something like this, which I'm sure looks horrendous to any experienced programmer, and won't run if you use it as is because it's just a snippet.

def getObjects( mode='', scrollListName='' ):
    print mode
    if mode == 'listSelected':
        objects = cmds.textScrollList( scrollListName, query=True, selectItem=True )
    if mode == 'listAll':
        objects = cmds.textScrollList( scrollListName, query=True, allItems=True )
    if mode == 'listByName':
        objects = ''
    if mode == 'selected':
        objects = cmds.ls(sl=True, sn=True)
    if mode == 'all':
        objects = cmds.ls(sl=True, sn=True)
    return objects

def exportInit(exportMode='', scrollListName='', ):  
    # duplicating arg names is getting confusing  
    # get selected objects from outside function
    selectedObjects = getObjects( mode=exportMode, scrollListName=scrollListName )
    print 'Selected objects are...', selectedObjects
    # export objects
    export( objects=selectedObjects, scrollListName=scrollListName )

def makeExportButtons( scrollListName='', buttons=None ):
    cmds.columnLayout( columnAttach=('both', 5), rowSpacing=10, columnWidth=250 )
    for buttonInfo in buttons:
        # more PyMEL
            command=pm.Callback( exportInit, 
                                 scrollListName= scrollListName ) )
    cmds.setParent( '..' )

def export( objects=None, scrollListName='' ): 
    mel.eval("FBXExportSmoothingGroups -v true")
    mel.eval("FBXExportHardEdges -v false")
    mel.eval("FBXExportTangents -v false")
    mel.eval("FBXExportSmoothMesh -v true")
    mel.eval("FBXExportInstances -v false")
    mel.eval("FBXExportReferencedContainersContent -v false")
    # mm.eval("FBXExportBakeResampleAll -v true")
    mel.eval("FBXExportUseSceneName -v false")
    mel.eval("FBXExportQuaternion -v euler")
    mel.eval("FBXExportShapes -v true")
    mel.eval("FBXExportSkins -v true")
    # Constraints
    mel.eval("FBXExportConstraints -v false")
    # Cameras
    mel.eval("FBXExportCameras -v false")
    # Lights
    mel.eval("FBXExportLights -v false")
    # Embed Media
    mel.eval("FBXExportEmbeddedTextures -v false")
    # Connections
    mel.eval("FBXExportInputConnections -v false")
    # Axis Conversion
    mel.eval("FBXExportUpAxis y")
    exported = []
    if scrollListName == 'modelList':
        # Exports all objects in list 
        for object in objects:
            if _fileType == 'FBX':
                print object
                mel.eval('FBXExport -f "'+modelDir + '/' + object + '.fbx" -s')
    if scrollListName == 'animList':
        # get checkbox booealn status
        forUnity = cmds.checkBox( 'unityNames', query=True, value=True )
        for object in objects:
            # take stored string and get integers back
            rangeMin = eval(saveData[object])[0]
            rangeMax = eval(saveData[object])[1]
            mel.eval("FBXExportBakeComplexAnimation -v true")
            mel.eval("FBXExportBakeComplexStart -v "+str(rangeMin) ) 
            mel.eval("FBXExportBakeComplexEnd -v "+str(rangeMax) ) 
            mel.eval("FBXExportBakeComplexStep -v 1")
            if forUnity:
                # add @ in anim names for Unity to recognize it
                mel.eval('FBXExport -f "'+ animDir + '/' + sceneName + '@' + object + '.fbx"-s')
                # else just add an underscore
                mel.eval('FBXExport -f "'+ animDir + '/' + sceneName + '_' + object + '.fbx"-s')

[Edit] Got the same error using partial inside Callback, "TypeError: 'functools.partial' object is not iterable # " Seems like the partial object doesn't evaluate when the button is pressed and it passes to the export function to be iterated over.

Last edited by RawMeat3000 : 04 April 2013 at 03:56 AM.
Old 04 April 2013   #6
Not sure what to add, except to reassure you that it does work. Maybe you didnt try the simple working example I gave you. Maybe it didnt work for you. But here it did (maya 2013). It calls a function and passes it another function, using partial, as one of the keyword arguments. The 2nd function is evaluated correctly when the button is clicked and prints a list of the selected objects.

I don't have time to study your new code, sorry. Proabably best to try and get it working in a simple example before you write it into the bigger script.

Old 04 April 2013   #7
Thread automatically closed

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.
Thread Closed share thread

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Society of Digital Artists

Powered by vBulletin
Copyright 2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump

All times are GMT. The time now is 11:17 AM.

Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.