Whenever you want something to happen when your selection in Maya changes, the first thing that comes into your mind might be Maya ScriptJobs.
However I find them very slow and not reliable, especially since they are wrapped in mel.
Better use a callback from OpenMaya’s messaging system.
This is how you do it:
You will have to create a function that is called every time the selection changes. Make it run fast and with lots of error checking to avoid making your tool too slow.
In your function, get the selection and evaluate what you want to do with it.
The function could look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from maya import OpenMaya #function to execute when selection changes def maya_selection_changed(*args, **kwargs): try: sel = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(sel) selection_iter = OpenMaya.MItSelectionList(sel) obj = OpenMaya.MObject() # Loop though iterator objects while not selection_iter.isDone(): # Now we can do anything with each of selected objects. # In this example lets just print path to iterating objects. selection_iter.getDependNode(obj) dagPath = OpenMaya.MDagPath.getAPathTo(obj) print dir(dagPath) print dagPath.fullPathName() print dagPath.partialPathName() #print dir(dagPath) selection_iter.next() except RuntimeError, err: print err |
Don’t worry, you don’t have to use maya API but you can use pymel or even maya.cmds instead.
In my example I just print the names of the selected nodes however I would avoid any prints as they are slowing down Maya.
As the next step you have to tell Maya to run this function when the selection has changed. Just connect it with the OpenMaya callback like so:
1 2 |
#create callback and store it in a variable selection_changed_callback = OpenMaya.MEventMessage.addEventCallback("SelectionChanged", maya_selection_changed) |
When you don’t need it anymore you’ll have to disable the function call by disconnecting from the callback like this:
1 2 |
#Remove callback again OpenMaya.MMessage.removeCallback(selection_changed_callback) |
Things to avoid
- too many tools that use the same type of callbacks
- forgetting to disconnect the callback when your tool closes
- print statements in the callback function
- heavy code or checks in your function which could slow down your function
Try it out and see for yourself how nice they are.
In the maya documentation you will find loads of other callback messages you can connect to.
2 thoughts on “OpenMaya Callbacks instead of Maya ScriptJobs”
Hi there, thanks for the tut, it’s pretty neat!
I’ve tried to implement a IK/FK match script with scriptJob. It’s working fine on the viewport but it’s buggy when i test it on animation so it’s kinda useless. I checked listEvents can be used for OM callbacks but couldn’t find something like ‘attributeChange’. What event can i use for callback to work with attribute(enum) change for this?
Hi, to first answer your question, check the OpenMaya.MNodeMessage.addAttributeChangedCallback() function. Check the docs.
Generally speaking I would not really use callbacks or scriptJobs to check for the state change of an attribute for something like IK/FK matching.
What we usually do is override the marking menu and let the user trigger the matching function.
The issue with callbacks is that they will slow down Maya depending on the callback type, what your function does and how many of those you have running.
So for instance we created a callback to check when the selection has changed. The callback triggers and runs a function. Depending on how you wrote that function it might be slow and therefore cause a delay every time the user clicks.
So the next problem is with an attribute change callback, imagine how often the attribute changes. You want to run the IK/FK matching once, not EVERY time the attribute changes during playback, I suppose.
However the OpenMaya.MNodeMessage.addAttributeChangedCallback does not get executed during playback, so this might just be what you want.
Also your matching function might change the attribute back and forth logically to get the transforms first, and then bake them. So always think of building in a FREEZE or MUTE logic to disable the callback while your matching routine changes the attribute so that you don’t trigger it again and again.
Good luck and happy scripting 🙂