使用消息

消息系统提供一种通知事件和交换信息的方法。

消息和参数

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 在函数调用返回之前立即通知处理程序和过滤器,这使得处理程序和过滤器能够立即对消息作出反应。

当您分发消息时,它会经历两个阶段:首先是隧道传递,然后是冒泡。在隧道传递阶段,消息从 Screen 节点(根节点)的第一个子节点沿节点树向下传递到消息发起的节点。从那里,消息再沿节点树冒泡回到根节点。

对消息做出反应

Kanzi 中的所有消息都是路由消息。当消息被分派时,系统通过称为隧道传递的过程,从 Screen 节点(根节点)的第一个子节点遍历到消息的源节点,然后通过称为冒泡的过程返回到根节点。当您希望节点对传递的消息做出反应时,请向这些节点添加消息处理程序或过滤器。消息过滤器拦截来自任何节点的消息,而消息处理程序仅监听来自特定源节点的消息。

在节点树中,每个通过的节点,系统都会查找处理程序和过滤器以处理已分派的消息。这使您可以在节点树中的任何位置安装处理程序和过滤器,以在消息到达目的地之前拦截消息,或从多个来源收集消息。

要注册对以下内容做出反应的消息处理程序和过滤器:

要删除所有类型的处理程序和过滤器,请使用 Node::removeMessageHandler。

要定义一个简单的示例节点,一个消息类型,两个适合消息处理程序的回调,以及一个用于验证回调调用的计数机制:

// 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 中使用消息