-
Notifications
You must be signed in to change notification settings - Fork 23
Tutorial 4: Callbacks
This tutorial assumes you've worked your way through the previous tutorials
Vanilla maya widgets trigger actions through the use of callbacks - functions that are assigned to pre-defined events such as a button push, the selection of a line in a treeview, or the resizing of a window.
- Scope When you assign the callback maya will need access to the function you want to call. That often creates tight coupling between the gui layout and the function you want to call. Moreover, managing these callbacks in maya can be a tricky subject.
- Parameters It's very common to have many gui items which do the same job, but which work on slightly different data: for example, buttons to create small, medium and large object are almost identical except for some information about the size of the object.
- Purpose. Gui work often involves a mix of behaviors that are quite distinct. Pressing a button might move something in your maya scene, expose a new set of controls in your window, and enable some buttons.
mGui tries to address all three of these problems with its event mechanism. Events try to address all three of the main weaknesses in conventional Maya gui programming; we'll point out how as we go along.
Lets start with the classic button handler.
from mGui.gui import *
from mGui.forms import *
def handler(*args, **kwargs):
print "I was pressed"
with Window() as w:
with FillForm() as f:
b = Button("press me")
b.command += handler
w.show()
This defines a function called handler
which is attached to the button. The important line is:
b.command += handler
This means that we are attaching the handler function to the button's command event. The "+=" is there because we can, if we want to, attach more than one function to a particular event; this simplifies the business of doing multiple things -- altering the Maya scene, showing or hiding controls, and providing feedback to the user -- with one interaction. To test it out, change the example so it looks like this:
def handler(*args, **kwargs):
print "I was pressed"
def other_handler(*args, **kwargs):
cmds.polyCube()
with Window() as w:
with FillForm() as f:
b = Button("press me")
b.command += handler
b.command += other_handler
w.show()
Now pressing the button prints out a message and creates a cube. You can disable one or the other of these functions using "-=".
For example:
b.command -= handler
will remove the printout but keep creating cubes.
You may have noticed that the handler functions both used the signature (*args, **kwargs)
. There's nothing magical here, that's just the standard python syntax for "some number of arguments, followed by some number of keywords".
mGui uses this form for all callback functions. This allows mGui to automatically tell your callbacks which object actually fired the callback -- something which takes a good bit of extra work in ordinary Maya usage. For example, say you have a number of buttons which do basically the same thing. You don't want to write a custom function for each of them -- ideally you'd like to reuse the functionality.
To make this easier, mGui includes a reference to the sending object in the **kwargs
that are passed to the handler. So in the case of multiple similar buttons, you could extend the example above like this:
def print_handler(*args, **kwargs):
print kwargs['sender'], "was pressed"
with Window() as w:
with VerticalForm() as f:
top = Button("top")
bottom = Buttom("bottom")
top.command += print_handler
bottom.command += print_handler
w.show()
In this case the printout will look like a regular maya widget path, something like window1|formLayout2|top
or something similar. However that's only because mGui objects return the path to their widgets if you print them -- the kwargs['sender']
contains the mGui object itself, not just a string -- so you can immediately reference all of the sender's properties in your handler. For example, this would toggle the background colors of the buttons between red and dark gray:
def color_handler(*args, **kwargs):
btn = kwargs['sender']
if btn.backgroundColor == (1,0,0):
btn.backgroundColor = (0.2, 0.2, 0.2)
else:
btn.backgroundColor = (1,0,0)
with Window() as w:
with VerticalForm() as f:
top = Button("top")
bottom = Buttom("bottom")
top.command += color_handler
bottom.command += color_handler
w.show()