Motionbuilder Buttons OnClick

Hey everyone. Quick question maybe someone can answer for me.

When you use button.OnClick.Add( def ) your button does as expected. But adding B[/B] the function name will fire off when that line is hit. I can see why that is happening but am wondering if there is a way to pass an arg with the button without having it call that function automatically?

Using button.OnClick.Add( def( arg ) ) will auto-fire, obviously.

Is OnClick is just limited in this way? Am I missing something obvious?

Thoughts? Thanks.
~Travis

Assuming you have a button and some function that takes arguments:


def do_something(x):
    return x

You’d probably want to use a lambda expression to create an anonymous function that applies whatever arguments you want applied when the button is clicked:


button.OnClick.Add(lambda: do_something(5))

This is roughly equivalent to:


def do_something_with_five():
    return do_something(5)

button.OnClick.Add(do_something_with_five)

Some people may also prefer:


from functools import partial

button.OnClick.Add(partial(do_something, 5))

If I recall, though, MotionBuilder callbacks expect two parameters (a sender object and an event), so you’d want to catch those arguments and throw them away:


button.OnClick.Add(lambda sender, event: do_something(5))

ya just use lambda, its because if you use the () on your function it passes the return of your function not the function its self.

but if you use lambda it is more or less defining a new function object that runs your function plus arguments.


button.OnClick.Add(lambda *args: yourFunc(yourArgs))

Excellent! Using Lambda is exactly what I needed.

Mobu does need those 2 other args for buttons. I found that both

 button.OnClick.Add( lambda control , event: func(arg) ) 

and

 button.OnClick.Add( lambda *args: func(arg) ) 

Seem to work interchangeably for what I need.

Thanks for the help!

ya if i don’t actually want to work with the augments the UI callback inserts, or if there are a lot of them, i just use *args it stores all the arguments in a list called args, for you to deal with later, **kwargs does the exact same thing for keyword arguments, just that it stores in a dict instead.

if your curios why this works, is because lambda, or more or less a easy way to define a nameless function, and the callback accepts only a function object, that it can execute at a later time. So this is a quick way to create that function object, that runs your wanted method or function with arguments.

You might also want to look at functools.partial. Partials are objects which bind a function and some number of arguments together into a callable object - might be useful if its too complex to compose all the functions inside a lambda expression