Houdini 18.5 PDG/TOPsを使ってタスクを実行する方法

イベントのハンドリング

PDGノードまたはグラフからイベントを制御するためのPython関数を登録することができます。

On this page

概要

PDGには、クック中に何かが起きた時にカスタムPythonコードを実行できるようにするために使用可能なイベントハンドルの仕組みが備わっています。 イベントフックは、クックの完了といった粗いグラフイベンに対してだけでなく、ステートの変更や依存関係の変更などのワークアイテム内の細かな変更に対して利用することもできます。 このイベントの全リストは、pdg.EventType APIリファレンスに載っています。

イベントハンドラーを登録するには、まず最初にpdg.Nodepdg.WorkItempdg.GraphContextのどれかを参照する必要があります。 一度TOPグラフがクックされると、hou.TopNodeからノードとグラフコンテキストにアクセスできるようになります。 pdg.GraphContext.workItemByIdpdg.EventworkItemIdを指定してワークアイテムを検索することで、そのワークアイテムを見つけることができます。

Houdini18より前のバージョンでは、ワークアイテムから発行されるイベントは、そのワークアイテムを所持しているノードとグラフコンテキストからも発行されていました。 つまり、イベントハンドラーをグラフコンテキストに追加するだけで、ワークアイテム、ノード、グラフのすべてのイベントをキャッチすることができましたが、これがもはや当てはまらなくなりました。ワークアイテムのイベントをキャッチできるようにするには、イベントハンドラーをワークアイテムに追加する必要があります。 一部のイベントは引き続き複数のオブジェクトから発行されますが、今ではその挙動は一部のイベントに固有なものです。

import hou
import pdg

topnode_path = '/tasks/topnet1/genericgenerator1'
top_node = hou.node(topnode_path)

# 大元のPDGグラフにアクセスできるようにするために、必ずTOPグラフをクックします。
top_node.executeGraph(False, False, False, True)

pdg_node = top_node.getPDGNode()
pdg_context = top_node.getPDGGraphContext()

イベントハンドラーを登録するAPIは、ノードオブジェクトとグラフコンテキストオブジェクトのどちらでも同じです。 pdg.Eventを1番目の引数として受け取る関数を定義することで、各ハンドラーが作成されます:

# ワークアイテムイベントを制御する関数を定義します。
def print_add(event):
    work_item = pdg_context.graph.workItemById(event.workItemId)
    print ("Work item '{}' was added to node {}".format(work_item.name, event.node.name))
    # ステートの変更を受信するためのリスナーをこの新しいワークアイテム上に追加します。

    def print_workitem_change(event):
        work_item = pdg_context.graph.workItemById(event.workItemId)
        print ('State Change for {}: {} -> {}'.format(work_item.name, event.lastState, event.currentState))
    work_item.addEventHandler(print_workitem_change, pdg.EventType.WorkItemStateChange)

# グラフレベルのイベントを制御する関数を定義します。
def print_done(event):
    print ("Graph cook complete!")

# ハンドラーを登録します。
node_handler = pdg_node.addEventHandler(print_add, pdg.EventType.WorkItemAdd)
context_handler = pdg_context.addEventHandler(print_done, pdg.EventType.CookComplete)

イベントを登録するコードの適切な配置場所は、セットアップによって異なります。 1つの選択肢として、ツールがクリックされた時にハンドラーを登録したいのであれば、シェルフツール内にコードを配置します。

ハンドラーを削除する方法

イベントハンドラーの処理が終わった後にそのハンドラーを削除したいことが時折あります。 ハンドラーを削除する1つの方法は、最初にハンドラーの追加で使用したオブジェクトに対してremoveEventHandlerメソッドをコールすることです:

pdg_node.removeEventHandler(node_handler)

イベント関数自体の中からハンドラーを削除することもできます。 それをする場合、ハンドラー関数を登録する時に追加でpass_handler=True引数を指定する必要があります。 この引数は、そのイベント関数がどのハンドラーに自身が関連付けられているのかを知るためのものです。 このイベント関数自体の中で、そのハンドラーに対してpdg.EventHandler.removeFromAllEmittersメソッドをコールすることができるようになります:

def print_done_and_remove(handler, event):
    print ("Graph cook complete!")

    # リッスンしているすべてのイベントからハンドラーの登録を解除します。
    handler.removeFromAllEmitters()

pdg_context.addEventHandler(print_done_and_remove, pdg.EventType.CookComplete, True)

トリガーUIが変更するイベント

PDGイベントは、それを発動した同じクックスレッド上でバックグラウンドで処理されます。 これは、一般的には、イベントハンドラー関数から他のクックを開始したり、パラメータを変更したり、UIダイアログを開くことが安全ではないことを意味します。 場合によっては、hdeferevalモジュールを使ってあなたのコードがバックグラウンドではなくメインスレッドで実行されるようにすることで、これらのアクションを実行することができます:

import hdefereval

# メッセージを表示するための関数を定義します。
def display_message(message):
    import hou
    hou.ui.displayMessage(message, title="Example Message from PDG")

# イベントハンドラーを定義します。
def display_event(event):
    hdefereval.executeDeferred(display_message, "An example message created in"
        " a PDG Event but displayed from the main thread!")

pdg_context.addEventHandler(display_event, pdg.EventType.CookComplete)

Note

現行PDG/TOPグラフを安全に再クック可能な唯一のイベントは、CookCompleteイベントです。 イベントハンドラー関数は、他のTOPネットワークをクックすることができますが、それをするためにhdeferevalモジュールを使用しなければなりません。

PDGオブジェクトから発行されるイベントのリスト

グラフコンテキストイベント:

  • pdg.EventType.CookComplete

  • pdg.EventType.CookError

  • pdg.EventType.CookWarning

  • pdg.EventType.DirtyAll

  • pdg.EventType.NodeCreate

  • pdg.EventType.NodeRemove

  • pdg.EventType.NodeRename

  • pdg.EventType.NodeSetScheduler (デフォルトスケジューラが設定されている時)

  • pdg.EventType.SchedulerAdded

  • pdg.EventType.SchedulerRemoved

  • pdg.EventType.UISelect

  • pdg.EventType.WorkItemAdd

  • pdg.EventType.WorkItemRemove

ノードイベント:

  • pdg.EventType.CookComplete

  • pdg.EventType.CookError

  • pdg.EventType.CookStart

  • pdg.EventType.CookWarning

  • pdg.EventType.DirtyStart

  • pdg.EventType.DirtyStop

  • pdg.EventType.NodeClear

  • pdg.EventType.NodeRename

  • pdg.EventType.NodeSetScheduler

  • pdg.EventType.WorkItemAdd

  • pdg.EventType.WorkItemRemove

  • pdg.EventType.WorkItemStateChange

ワークアイテムイベント:

  • pdg.EventType.WorkItemAddDep

  • pdg.EventType.WorkItemAddParent

  • pdg.EventType.WorkItemMerge

  • pdg.EventType.WorkItemMerge

  • pdg.EventType.WorkItemRemoveDep

  • pdg.EventType.WorkItemResult

  • pdg.EventType.WorkItemSetFile

  • pdg.EventType.WorkItemSetFloat

  • pdg.EventType.WorkItemSetGeometry

  • pdg.EventType.WorkItemSetInt

  • pdg.EventType.WorkItemSetPyObject

  • pdg.EventType.WorkItemSetString

  • pdg.EventType.WorkItemStateChange

PDG/TOPsを使ってタスクを実行する方法

基本

初心者向けチュートリアル

次のステップ

リファレンス