この記事はTakumi Akashiro ひとり Advent Calendar 2020の22日目の記事です。
始めに
MEventMessage、ScriptJobどちらもEventが発火したら登録したコールバック関数を実行させる仕組みですが、
実はMEventMessageとScriptJobの実行タイミングは違います。
コマンドリファレンスをしっかりと読んだことがある方は、何故かそうなる理解できると思います。
まずはどちらも試してみる
今回は分かりやすいSelectionChanged Eventにフックさせていきます
#! python2
# encoding: utf-8
from maya import cmds
def print_func(text):
print(text)
if __name__ == '__main__':
if 'scriptjob_id' in globals() and cmds.scriptJob(ex=scriptjob_id):
cmds.scriptJob(kill=scriptjob_id)
scriptjob_id = cmds.scriptJob(event=["SelectionChanged", "print_func('SelectionChanged: ScriptJob')"])
#! python2
# encoding: utf-8
from maya.api import OpenMaya
def print_func(text):
print(text)
if __name__ == '__main__':
if 'm_event_message_cbk_id' in globals(): # コールバックIDが生きてるか確認する手段が思いつかなったのでtry-exceptで誤魔化す。
try:
OpenMaya.MEventMessage.removeCallback(m_event_message_cbk_id)
except RuntimeError, UnicodeDecodeError: # UnicodeDecodeErrorは日本語環境用
pass
m_event_message_cbk_id = OpenMaya.MEventMessage.addEventCallback("SelectionChanged", print_func, 'SelectionChanged: MEventMessage')
ScriptJobもMEventMessageも同じく動いている'ように'見えますね!
MEventMessageとScriptJob、その違い
ではScriptEditorで以下を実行してみます。
#! python2
# encoding: utf-8
from maya import cmds
for x in range(3):
cmds.select(cmds.ls(sl=True))
なんということでしょう!
ScriptJobの方は1回しか実行されてないですが、MEventMessageは3回とも実行されててますね。
どうしてそうなるのか
これにはScriptjobの実行タイミングに秘密があります。
公式リファレンスを読んでみましょう。
スクリプト ジョブは、インタラクティブなアプリケーションでイベント ループに結び付けられています。
このジョブはアイドル イベント中に実行されます。
このことは、スクリプト ジョブがバッチ アプリケーションに存在しないことを意味しています。scriptJob コマンドは、バッチ モードでは何も行いません。
Command Reference: scriptJob - Maya ヘルプ より抜粋
というわけでScriptJobは処理がいったん終わって、アイドル状態にならないと動かないのです。
なのでScriptJobとMEventMessageを併用した状態で、さっきのスクリプトにprint文を足して動かすと……
#! python2
# encoding: utf-8
from maya import cmds
print('-'*10 + '\nStart')
for x in range(3):
print('Selection_before: %s' % x)
cmds.select(cmds.ls(sl=True))
print('Selection_after: %s' % x)
if x != 2:
print('-'*10)
print('-'*10 + '\nEnd')
処理直後にMEventMessageが走り、処理が完全に終わったあと、
Mayaがアイドルになった段階でScriptJobがやっと実行されるわけです。
締め
違いが分かると、処理回数をできる限り減らすためにScriptJobを使ったり、
厳密に監視するためにMEventMessageを使うなど、使い方が分けられると思います。
Eventにフックさせる系は便利ですが、引き換えに操作レスポンスを悪くする可能性があるので、
ここらへんは意識できるといいですね!