メッセージの使用

メッセージシステムには、イベントを通知したり情報をやり取りしたりする手段が備わっています。

メッセージと引数

MessageArguments は、メッセージで渡される引数の基底クラスです。Kanzi は、異なるノードやトリガーのための組み込みメッセージタイプを提供します。例えば、Button: Click トリガーのための ButtonConcept::ClickedMessageArguments メッセージや、Page Activated トリガーのための Page::ActivatedMessageArguments メッセージです。

MessageArguments クラスを拡張して、独自のメッセージタイプを書くことができます。

メッセージタイプの説明:

PropertyType オブジェクトを使用して、メッセージ引数を記述およびアクセスできます。MessageArguments::setArgument 関数は引数を設定し、MessageArguments::getArgument 関数は引数を取得します。引数の基礎となるストレージタイプには、float、boolean、vector3 などがあります。

Kanzi Studio でカスタムメッセージを作成する

Kanzi Studio でカスタムメッセージを作成するには、

  1. Library Alt を押しながら右クリック Message Types で、Message Type を選択します。

    ../../_images/message-type-in-library.png
  2. Properties セット内で:

    • Category を、コンテキストメニューでこのメッセージを表示したいカテゴリー Kanzi Studio に設定します。

    • Arguments をメッセージタイプが受け入れる引数にします。

    • Routing Mode をメッセージタイプのルーティングモードに。

      • Tunneling モードは、受信ノードの最も外側の親ノードを通してメッセージを渡します。

      • Bubbling モードは、受信ノードの最も近い親ノードを通じてメッセージを渡します。

    ../../_images/message-type-arguments.png

トリガーメッセージの処理設定 を参照してください。

Kanzi Engine APIでメッセージを使用する

メッセージのディスパッチ

メッセージを送信するには、Node::dispatchMessage を使用します。この関数はメッセージのタイプと引数を定義し、そのメッセージタイプに登録されているノードのすべてのハンドラとフィルタを呼び出します。Node::dispatchMessage は、関数呼び出しが戻る直前にハンドラとフィルタに通知し、ハンドラとフィルタがメッセージに即座に反応できるようにします。

メッセージをディスパッチすると、2つのフェーズで移動します。最初にトンネリング、次にバブリングです。トンネリングフェーズでは、メッセージは Screen ノード(ルートノード)の最初の子ノードからメッセージが発生したノードまでノードツリーを下って移動します。そこからメッセージはノードツリーをバブリングしてルートノードに戻ります。

メッセージに反応する

Kanzi 内のすべてのメッセージはルーティングメッセージです。メッセージがディスパッチされると、システムは Screen ノード(ルートノード)の最初の子ノードからメッセージのソースノードまでノードツリーを通過するトンネリングと呼ばれるプロセスを行い、その後、バブリングと呼ばれるプロセスでノードツリーをルートノードまで戻ります。メッセージが通過したときにノードが反応するようにしたい場合は、それらのノードにメッセージハンドラまたはフィルタを追加します。メッセージフィルタは任意のノードからのメッセージをインターセプトし、メッセージハンドラは特定のソースノードからのメッセージのみをリッスンします。

ノードツリー内の各ノードを通過する際に、システムは送信されたメッセージのハンドラーとフィルタを探します。これにより、ノードツリーの任意の場所にハンドラーとフィルタを設置して、メッセージが目的地に到達する前に傍受したり、複数のソースからメッセージを収集したりすることができます。

メッセージハンドラとフィルタを登録して、以下に反応するようにします:

すべての種類のハンドラーとフィルタを削除するには、Node::removeMessageHandler を使用します。

シンプルな例のノードを定義するには、1つのメッセージタイプ、メッセージハンドラに適した2つのコールバック、およびコールバックの呼び出しを検証するためのカウントメカニズムを使用します。

// Counts how many times the callbacks are invoked to verify that the calls occur.
static int callCount = 0;

// Define an example node, which presents a message type and a callback method.
class ExampleNode : public EmptyNode2D
{
public:
    // An example message type.
    static MessageType<MessageArguments> exampleMessageType;

    // Create the node.
    static ExampleNodeSharedPtr create(Domain* domain, string_view name)
    {
        ExampleNodeSharedPtr node = make_polymorphic_shared_ptr<EmptyNode2D>(new ExampleNode(domain, name));
        node->initialize();
        return node;
    }

    // An example callback method.
    void exampleNodeCallback(MessageArguments& message)
    {
        // To let the message continue moving in the node tree, set the message to not handled.
        message.setHandled(false);
        ++callCount;
    }

private:
    // Construct the node.
    explicit ExampleNode(Domain* domain, string_view name) :
        EmptyNode2D(domain, name)
    {
    }
};

// An example callback function.
void exampleCallback(MessageArguments& message)
{
    message.setHandled(false);
    ++callCount;
}

// The message type definition.
MessageType<MessageArguments> ExampleNode::exampleMessageType(kzMakeFixedString("ExampleNode.exampleMessageType"), nullptr);

ノード自体によって送信されたメッセージを Node::addMessageHandler で消費するハンドラーを追加するには:

// Initialize a node.
ExampleNodeSharedPtr node = ExampleNode::create(domain, "node");

// Add a message handler that intercepts messages dispatched from the node itself.
Node::MessageSubscriptionToken token = node->addMessageHandler(ExampleNode::exampleMessageType, &exampleCallback);

Node::removeMessageHandler を使用してハンドラーを削除するには:

// Remove the handler that intercepts messages dispatched from the node itself.
node->removeMessageHandler(token);

Node::addMessageHandler でバブリングハンドラーを追加するには:

// Initialize a child node.
EmptyNode2DSharedPtr child = EmptyNode2D::create(domain, "child");

// Set the node you created earlier to be the parent of the child node.
node->addChild(child);

// Add a bubbling message handler that accepts messages from the child node.
Node::MessageSubscriptionToken bubblingToken = node->addMessageHandler(ExampleNode::exampleMessageType, function<void(MessageArguments&)>(&exampleCallback), child.get());

Node::removeMessageHandler でバブリングハンドラを削除するには:

// Remove the bubbling handler.
node->removeMessageHandler(bubblingToken);

Node::addTunnelingFilter を使用してトンネリングフィルタを追加するには:

// Add a message filter that intercepts tunneling messages.
Node::MessageSubscriptionToken tunnelingToken = node->addTunnelingFilter(ExampleNode::exampleMessageType, node.get(), &ExampleNode::exampleNodeCallback);

Node::removeMessageHandler でトンネリングフィルタを削除するには:

// Remove the tunneling filter.
node->removeMessageHandler(tunnelingToken);

メッセージを送信するには、Node::dispatchMessage を使用します。

// Initialize the message that you want to dispatch.
MessageArguments message;

// Dispatch the created message from the child node. If the message dispatcher has any handlers
// or filters added for ExampleNode::exampleMessageType, Kanzi invokes their callbacks immediately.
child->dispatchMessage(ExampleNode::exampleMessageType, message);

関連項目

入力マニピュレータの使用

トリガー (Triggers)

トリガーの使用

Java メッセージ

Lua でのメッセージの使用