Pymel Callbacks...this should be easy

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
  05 May 2014
Pymel Callbacks...this should be easy

After reading the Pymel docs I was lead to believe that anyone who isn't a fool will use Callbacks for a button command. They have worked great for simple situations, but what about using the returned value from another procedure. This works with lamdas...and there must be a way to do it with Callbacks right?

Muchos Puntos to the master coder who can get both buttons to work:
import pymel.core as pm

def bar():
    return 'IT WORKED!'

def foo(thing):
    print thing

pm.window()
pm.rowLayout(nc=3)
pm.button('ABTN', command=pm.Callback(foo, bar))
pm.button('BBTN',command=lambda *args:foo(bar()))
pm.showWindow()
 
  05 May 2014
It's working perfectly fine, you are just passing the wrong argument.
You are giving it bar, which identifies a function, so when it prints the argument it prints the string equivalent of what you passed it, which is the logical address of that function.
You want to pass it the result of your function you return, so instead of bar you're supposed to pass it bar(), which will run the function, return the string, and pass it along.

It works in the lambda because you are doing exactly that, executing the function instead of passing it directly.
It's nothing to do with pymel as much as understanding of some fairly fundamental concepts of Python
__________________
Come, Join the Cult http://www.cultofrig.com - Rigging from First Principles
 
  05 May 2014
Thanks for the tip.
I tried a million combinations, and that was the one I missed!
Ah, fundamentals, those are nice aren't they!
 
  05 May 2014
More fundamentals please....

Well, maybe I did try the setup you mentioned before.
But it isn't working that way with callbacks any way I try.
It's like it doesn't fully execute the proc I am supplying it.
In basic cases it works. But try something like this and it doesn't:
***Any thoughts are greatly appreciated!*****
***EDIT: BTW, the Callback button is also executing bar on creation...which is not cool.

import pymel.core as pm

def bar():
    print 'RUNNING'
    try:
        nux=pm.ls(type='nucleus')
        if nux[0].enable.get():
            for enx in nux:
                enx.enable.set(False)
            return False
        else:
            for enx in nux:
                enx.enable.set(True)
            return True
    except:
        pm.warning('No nucleus nodes in scene.')
        return False

def foo(thing):
    print thing

pm.window()
pm.rowLayout(nc=3)
pm.button('ABTN', command=pm.Callback(foo, bar()))
pm.button('BBTN',command=lambda *args:foo(bar()))
pm.showWindow()
 
  05 May 2014
Hi Benjamin, I think you were almost correct in your first post. You dont want to execute the function when you declare the callback, so you were correct in passing in the object. But then you need to execute the function in foo.

def bar():
 	print 'RUNNING'
 	try:
 		nux=pm.ls(type='nucleus')
 		if nux[0].enable.get():
 			for enx in nux:
 				enx.enable.set(False)
 			return False
 		else:
 			for enx in nux:
 				enx.enable.set(True)
 			return True
 	except:
 		pm.warning('No nucleus nodes in scene.')
 		return False
 
 def foo(thing):
 	print thing()
 
 pm.window()
 pm.rowLayout(nc=3)
 pm.button('ABTN', command=pm.Callback(foo, bar))
 pm.button('BBTN',command=lambda *args:foo(bar))
 pm.showWindow()


So "bar" and not "bar()" in both the callback and lambda, I think, and then "print thing()"

David
__________________
http://www.djx.com.au
 
  05 May 2014
Oy, so crazy.
Hmmm, it seems that there is an issue with my nucleus script somewhere.
It works correctly with the lambda, but doesn't with the Callback.
There is a flaw in my script in the fact that the else statement within the try shouldn't ever fire, since the failing of the if statement would cause the exception to fire and not the else...I guess.
But lambda is like a honey badger and lambda don't care...it 'works' in spite of my bad coding.
Strange indeed.
 
  05 May 2014
David,
On further examination of your example, I see what you did with changing:
print thing
to
print thing()

But now this requires the original argument to be a function, which seems scary to me.
Maybe I am just overly squemish about this. Is this limitation of pm.Callbacks? That they can't use the returned value of the first procedure in the second?
 
  05 May 2014
Originally Posted by animatedfox: But now this requires the original argument to be a function, which seems scary to me.
Maybe I am just overly squemish about this. Is this limitation of pm.Callbacks? That they can't use the returned value of the first procedure in the second?

Callback mechanisms are commonly accepting function objects (or equivalents in other languages). There is nothing to be afraid off, it reduces spaghetti code (of which UI work is inevitably a victim) considerably.
Python treats everything as an object, passing a function along as one is perfectly safe if you know what you're doing, and it's a common practice in callback and event systems.

Don't be squeamish, dive in the deep end.
__________________
Come, Join the Cult http://www.cultofrig.com - Rigging from First Principles
 
  05 May 2014
If you use lambda or partial you can supply arguments, if arugmeants aren't needed i just dont even bother with lambda or partial, and just directly pass the function object in.

What lambda is essentially doing is creating a function, to run your function then returning it as a function object.

So if you use lambda you can have the () and args if you are passing directly dont use the () since that tells python to run tthe function not pass it.

Also I find UI work much easier and cleaner if you do it all in one class instead of a bunch of loose functions, since this way you can easily pass data around with self.
__________________
Twitter - GitHub
------------------
My Scripts - Maya tools and workflow scripts
psLink - Maya PhotoShop intergration.

Last edited by CMCPasserby : 05 May 2014 at 09:30 AM.
 
  05 May 2014
Good tips everyone thanks.
I get the tip about UI stuff contained within a class. Definitely easier.
In this case I am building a suite of standalone procs and a shelf with access to those procs. But the theory is that the tools should also be callable from outside the main shelf/UI. A simple request, that makes things a little more involved than I had hoped.

This was my big hesitation on using a function for an argument in this case.
I totally understand ThE_JacO's assertion that this is cool and powerful.
I just want to keep things as 'string', 'int', based as possible.

Thanks again for the tips all...I really appreciate it.
~Ben
 
  05 May 2014
Ya I keep only ui stuff in my ui class, if the ui needs data from elsewhere I just make ui methods to interact with other objects, to get or set data. As a result the actul functnality can be used with out the ui.

Also dont worry about keeping functions out of your args passing a function with its () as a arg is no different than passing its return to a function, just less steps involved.
__________________
Twitter - GitHub
------------------
My Scripts - Maya tools and workflow scripts
psLink - Maya PhotoShop intergration.
 
  05 May 2014
It's fine to keep focus on primitive data types - but using the string based call method makes it very hard to write maintainable tools. All the functions you call via strings have to be in the global namespaces - which means you have to (a) figure out how to get your functions into the global namespace, which is not trivial if they are organized into modules and classes and (b) if you reuse function names you'll never get be sure which function you'll get when you pass that string.

String callbacks = bad idea unless you're calling mel.
 
  05 May 2014
Dude, you guys are all brilliant!
I have so much to learn here.

print 'Onward!'
 
reply 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
CGSociety
Society of Digital Artists
www.cgsociety.org

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

All times are GMT. The time now is 02:20 AM.


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