使用消息¶
消息系统提供一种通知事件和交换信息的方法。
消息和参数¶
MessageArguments 是在消息中传递的参数的基类。Kanzi 为不同的节点和触发器提供内置消息类型。例如,Button: Click 触发器的 ButtonConcept::ClickedMessageArguments 消息和 Page Activated 触发器的 Page::ActivatedMessageArguments 消息。
您可以通过编写自己的消息类型来扩展 MessageArguments 类。
消息类型描述:
事件或信息的性质
例如,
ClickManipulator::ClickMessage和ListBoxConcept::ItemSelectedMessage。描述消息内相关数据的参数
例如,
InputManipulator::InputMessageArguments::HitTestPointProperty和ListBoxConcept::ItemSelectedMessageArguments::SelectedItemIndexProperty属性。
您可以使用 PropertyType 对象描述和访问消息参数。MessageArguments::setArgument 函数设置参数,MessageArguments::getArgument 函数检索参数,使用参数的底层存储类型,例如 float、boolean 和 vector3。
在 Kanzi Studio 中创建自定义消息¶
要在 Kanzi Studio 中创建自定义消息:
在 Library 按 Alt 并右键单击 Message Types 中选择 Message Type。
在 Properties 集中:
将 Category 到您希望 Kanzi Studio 在上下文菜单中显示此消息的类别。
Arguments 到消息类型接受的参数。
Routing Mode 到消息类型的路由模式。
Tunneling 模式通过接收节点的最外层父节点传递消息。
Bubbling 模式通过接收节点的最近父节点传递消息。
请参阅 设置触发器消息的处理。
使用 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);