扩展 Kanzi Engine 的功能

使用 Kanzi Engine 插件,您可以扩展 Kanzi Engine 的功能,并设置 Kanzi Studio 如何显示您创建的自定义内容:

创建自定义节点和属性类型

在 Kanzi Engine 插件中,您可以创建具有自定义属性类型的自定义节点。您可以设置 Kanzi Studio 如何显示这些节点并让用户与之交互。

要使用自定义属性类型创建自定义节点:

  1. 要将有关自定义节点的信息传递给 Kanzi Studio,请在描述节点的地方声明元数据:

    1. 在您的 Kanzi Engine 插件项目的 hpp 文件中,在元类定义之后,声明返回元数据的函数:

      ...
      KZ_METACLASS_END()
      
      static kanzi::PropertyTypeEditorInfoSharedPtr makeEditorInfo();
      ...
      
    2. 在您的 Kanzi Engine 插件项目的 cpp 文件中,为您的自定义节点创建元数据。

      例如,要创建工具提示并设置自动添加和常用属性,添加此代码片段:

      PropertyTypeEditorInfoSharedPtr MyPlugin::makeEditorInfo()
      {
          return PropertyTypeEditorInfoSharedPtr(
              KZ_DECLARE_EDITOR_METADATA(
                  // Set the name that you want to use for your node in Kanzi Studio.
                  metadata.displayName = "My Node";
                  // Set the tooltip that you want to use in the Kanzi Studio Create menu.
                  metadata.tooltip = "This example custom node uses custom properties.";
                  // Add the Horizontal Alignment and Vertical Alignment properties to the node.
                  metadata["AutomaticallyAddedProperties"] = "Node.HorizontalAlignment, Node.VerticalAlignment";
                  // Add the State Manager property as a frequently used property which users can add by clicking next to the property name.
                  metadata["FrequentlyAddedProperties"] = "Node.StateManager";
                  // Let the user add the Focusable property using the Add Property context menu or the context tab of the Add Properties window.
                  metadata["ContextProperties"] = "Node.Focusable";
              ));
      }
      
      ../../_images/create-custom-component-node-with-tooltip.png ../../_images/metaclass-metadata-properties.png
  2. 创建自定义属性类型及其元数据。

    例如:

    1. 在您的 Kanzi Engine 插件项目的 hpp 文件中,替换

      KZ_METACLASS_BEGIN(MyPlugin, Node3D, "CustomComponentType")
      KZ_METACLASS_END()
      

      通过

      // String property
      static kanzi::PropertyType<kanzi::string> StringProperty;
      // String reference to a node
      static kanzi::PropertyType<kanzi::string> NodeRefByStringProperty;
      // String reference to a prefab
      static kanzi::PropertyType<kanzi::string> PrefabRefByStringProperty;
      // Shared pointer reference to a prefab
      static kanzi::PropertyType<kanzi::ResourceSharedPtr> PrefabRefBySharedPtrProperty;
      // Shared pointer reference to a material
      static kanzi::PropertyType<kanzi::ResourceSharedPtr> MaterialRefBySharedPtrProperty;
      
      KZ_METACLASS_BEGIN(MyPlugin, Node3D, "MyNode")
          // Add the property types to the class metadata.
          KZ_METACLASS_PROPERTY_TYPE(StringProperty)
          KZ_METACLASS_PROPERTY_TYPE(NodeRefByStringProperty)
          KZ_METACLASS_PROPERTY_TYPE(PrefabRefByStringProperty)
          KZ_METACLASS_PROPERTY_TYPE(PrefabRefBySharedPtrProperty)
          KZ_METACLASS_PROPERTY_TYPE(MaterialRefBySharedPtrProperty)
      KZ_METACLASS_END()
      
    2. 在您的 Kanzi Engine 插件项目的 cpp 文件中,定义自定义属性类型。在每个属性类型定义中,设置这些参数:

      1. Kanzi Studio 的属性类型的完全限定名称。

      2. 属性类型的默认值。请参阅 默认属性值 和 属性优先级。

      3. 属性类型更改标志指示更改属性值的影响。请参阅 属性类型更改标志 和 PropertyTypeChangeFlag。

        要不使用任何更改标志,请将参数设置为 0。

      4. 属性类型的值是否可继承。请参阅 可继承的属性类型。

      5. 关于 Kanzi Studio 的属性类型的元数据。请参阅 在 Kanzi Studio 中显示 Kanzi Engine 插件自定义类型的参考。。

      例如,要定义您在上一步中创建的自定义属性类型:

      • 使用一行文本编辑器的字符串属性:

        // Creates a string property.
        // This example does not set the editor. If you do not set the editor, Kanzi Studio uses
        // the default editor for this property type.
        PropertyType<string> MyPlugin::StringProperty(
            kzMakeFixedString("MyPlugin.String"), "", 0, false,
            KZ_DECLARE_EDITOR_METADATA(
                metadata.displayName = "String";
            ));
        
        ../../_images/custom-component-string.png
      • 引用 3D 节点的字符串,用户可从下拉菜单中选择节点:

        // Creates a string reference to a node.
        PropertyType<string> MyPlugin::NodeRefByStringProperty(
            kzMakeFixedString("MyPlugin.NodeRefByString"), "", 0, false,
            KZ_DECLARE_EDITOR_METADATA(
                metadata.displayName = "Node Reference by String";
                // When you set valueProvider to ProjectObject:Node3D,
                // Kanzi Studio automatically uses the Node 3D selector editor.
                metadata.valueProvider = "ProjectObject:Node3D";
            ));
        
        ../../_images/custom-component-node-reference-by-string.png
      • 引用预设件的字符串,用户可从下拉菜单中选择预设件:

        // Creates a string reference to a prefab resource.
        PropertyType<string> MyPlugin::PrefabRefByStringProperty(
            kzMakeFixedString("MyPlugin.PrefabRefByString"), "", 0, false,
            KZ_DECLARE_EDITOR_METADATA(
                metadata.displayName = "Prefab Reference by String";
                // When you set valueProvider to ProjectObject:PrefabTemplate,
                // Kanzi Studio automatically uses the Prefab template selector editor.
                metadata.valueProvider = "ProjectObject:PrefabTemplate";
            ));
        
        ../../_images/custom-component-prefab-reference-by-string.png
      • 引用预设件资源的共享指针,用户可从下拉菜单中选择预设件资源:

        // Creates a shared pointer reference to a prefab resource.
        PropertyType<ResourceSharedPtr> MyPlugin::PrefabRefBySharedPtrProperty(
            kzMakeFixedString("MyPlugin.PrefabRefBySharedPtr"), ResourceSharedPtr(), 0, false,
            KZ_DECLARE_EDITOR_METADATA(
                metadata.displayName = "Prefab Reference by Shared Pointer";
                // When you set valueProvider to ProjectObject:PrefabTemplate,
                // Kanzi Studio automatically uses the Prefab template selector editor.
                metadata.valueProvider = "ProjectObject:PrefabTemplate";
            ));
        
        ../../_images/custom-component-prefab-reference-by-shared-pointer.png
      • 引用材质资源的共享指针,用户可从下拉菜单中选择材质资源:

        // Creates a shared pointer reference to a material resource.
        PropertyType<ResourceSharedPtr> MyPlugin::MaterialRefBySharedPtrProperty(
            kzMakeFixedString("MyPlugin.MaterialRefBySharedPtr"), ResourceSharedPtr(), 0, false,
            KZ_DECLARE_EDITOR_METADATA(
                metadata.displayName = "Material Reference by Shared Pointer";
                // When you set valueProvider to ProjectObject:Material,
                // Kanzi Studio automatically uses the Material dropdown editor.
                metadata.valueProvider = "ProjectObject:Material";
            ));
        
        ../../_images/custom-component-material-reference-by-shared-pointer.png
  3. 构建并安装您的插件。请参阅 将 Kanzi Engine 插件添加到 Kanzi Studio 项目中。。

  4. 在 Library > Kanzi Engine Plugins 的 Kanzi Studio 中选择您的插件。在 Properties 中,您可以看到自定义属性类型。

    ../../_images/myplugin-properties.png
  5. 在 Node Tree 中,选择要添加节点的节点、按 Alt 并右键单击,并选择您的自定义节点。

    ../../_images/create-custom-component-node.png
  6. (可选) 设置您创建的节点类型的图标。请参阅 设置节点类型的图标。

  7. (可选) 默认情况下,Kanzi Studio 将自定义属性作为常用属性添加到您为其创建属性类型的节点类型中。要设置 Kanzi Studio 建议属性的节点类型,以及 Kanzi Studio 是自动添加属性还是让用户添加,请设置 metadata.host 属性。请参阅 host。

    ../../_images/custom-component-properties.png

创建自定义消息类型

您可以创建和配置用于向应用程序添加功能的自定义消息类型。例如,使用消息类型使您的节点类型对事件做出反应。

对于您定义的每个自定义消息类型,Kanzi Studio 创建一个消息操作和一个消息触发器类型,分别允许您分派和响应该消息类型。

当您使用 Kanzi Connect 时,您可以使用自定义消息类型来获取有关您的应用程序使用的 Kanzi Connect 服务器或服务的信息。

创建自定义消息触发器

在 Kanzi Engine 插件中,您可以创建一个自定义消息类型,该类型在 Kanzi Studio 中显示为消息触发器。消息类型使您能够在某个事件发生时订阅通知。

例如,要允许 Kanzi Studio 用户添加一个名为 On Fuel Level Changed 的消息触发器,当名为 Fuel Indicator 的自定义节点的燃油水平发生变化时触发:

  1. 在您的节点类中,创建表示自定义消息类型的类并定义该消息类型:

    // Represents message arguments of FuelIndicator.OnFuelLevelChanged message type.
    class OnFuelLevelChangedMessageArguments : public MessageArguments
    {
    public:
        KZ_MESSAGE_ARGUMENTS_METACLASS_BEGIN(OnFuelLevelChangedMessageArguments, MessageArguments, "On Fuel Level Changed Message Arguments")
        KZ_METACLASS_END()
    };
    
    // Define the message type of the FuelIndicator.OnFuelLevelChanged message.
    static MessageType<OnFuelLevelChangedMessageArguments> OnFuelLevelChangedMessage;
    
  2. 创建一个函数,当燃料水平变化时分派消息:

    // Sends a FuelIndicator.OnFuelLevelChanged message.
    void onFuelLevelChanged(int fuelLevel)
    {
        OnFuelLevelChangedMessageArguments messageArguments;
        dispatchMessage(OnFuelLevelChangedMessage, messageArguments);
    }
    
  3. 声明消息的元数据:

    MessageType<FuelIndicator::OnFuelLevelChangedMessageArguments> FuelIndicator::OnFuelLevelChangedMessage(
        kzMakeFixedString("Message.FuelIndicator.OnFuelLevelChanged"),
        KZ_DECLARE_EDITOR_METADATA(
            // Set the name of the message the way you want to show it in Kanzi Studio.
            metadata.displayName = "On Fuel Level Changed";
            // Set the tooltip for the message.
            metadata.tooltip = "Fuel Indicator sets off this trigger when its level changes.";
            // Do not show the message in the trigger actions dropdown menu.
            // You show the message as a trigger.
            metadata.sendable = "False";));
    
    ../../_images/on-fuel-level-changed-trigger.png

创建自定义动作

在 Kanzi Engine 插件中,您可以创建一个自定义消息类型,Kanzi Studio 将其显示为一个操作。

例如,允许 Kanzi Studio 用户向触发器添加一个名为 Fuel Indicator: Update Level 的操作,该操作显示在 Text Block 3D 节点中名为 Fuel Indicator 的自定义节点的级别:

  1. 在您的 Kanzi Engine 插件项目的 hpp 文件中,创建表示自定义消息类型的类并定义该消息类型:

    // Represents the message arguments of the FuelIndicator.UpdateLevel message.
    class FuelIndicatorUpdateLevelMessageArguments : public MessageArguments
    {
    public:
    
        KZ_MESSAGE_ARGUMENTS_METACLASS_BEGIN(FuelIndicatorUpdateLevelMessageArguments, MessageArguments, "Fuel Indicator Update Level Message Arguments")
            KZ_METACLASS_PROPERTY_TYPE(FuelIndicatorLevelProperty)
        KZ_METACLASS_END()
    
        // The property type which represents the value of the Fuel Indicator node.
        static PropertyType<int> FuelIndicatorLevelProperty;
    
        // Returns the value of the Fuel Indicator message argument.
        int getFuelIndicatorLevel()
        {
            return getArgument(FuelIndicatorLevelProperty);
        }
    
    };
    
    // The message type of the FuelIndicator.UpdateLevel message.
    static MessageType<FuelIndicatorUpdateLevelMessageArguments> FuelIndicatorUpdateLevelMessage;
    
  2. 在您的 Kanzi Engine 插件项目的 hpp 文件中定义 FuelIndicator.UpdateLevel 消息的消息处理程序:

    // The message handler for the FuelIndicator.UpdateLevel message.
    // Shows the level of the Fuel Indicator in a Text Block 3D node.
    void fuelIndicatorUpdateLevelHandler(FuelIndicatorUpdateLevelMessageArguments& arguments)
    {
        // Get the level of the Fuel Indicator node.
        m_currentLevel += arguments.getFuelIndicatorLevel();
    
        // Show the level of the Fuel Indicator node in a Text Block 3D node.
        TextBlock3DSharedPtr textBlock = m_textBlockReference.get();
    
        if (textBlock)
        {
            textBlock->setText(to_string(m_currentLevel));
        }
    }
    
  3. 在包含 Application::initialize 函数的 hpp 文件中注册 FuelIndicator.UpdateLevel 消息的消息处理程序:

    void initialize()
    {
        ...
    
        // Register the message handler for the FuelIndicator.UpdateLevel message.
        addMessageHandler(FuelIndicatorUpdateLevelMessage, this, &FuelIndicator::fuelIndicatorUpdateLevelHandler);
    }
    
  4. 在您的 Kanzi Engine 插件项目的 cpp 文件中声明 FuelIndicator.UpdateLevel 消息的元数据。

    Kanzi Studio 根据您声明消息类型的父类元数据的 displayName 属性的值,在创建上下文菜单中对消息类型进行分组。您可以通过设置 category 属性来覆盖此信息。

    MessageType<FuelIndicator::FuelIndicatorUpdateLevelMessageArguments> FuelIndicator::FuelIndicatorUpdateLevelMessage(
        kzMakeFixedString("Message.FuelIndicator.UpdateLevel"),
        KZ_DECLARE_EDITOR_METADATA(
            // Set the name of the message the way you want to show it in Kanzi Studio.
            metadata.displayName = "Fuel Indicator: Update Level";
            // Do not show the message as a trigger.
            // You show the message in the trigger actions dropdown menu.
            metadata.listenable = "False";
            // Set the category to override the name of default context menu item for grouping message actions.
            metadata.category = "Fuel";));
    
    ../../_images/update-level-action.png

创建自定义节点组件

自定义节点组件是一个独立的逻辑片段,您可以在 Kanzi Engine 插件中实现,并可以附加到任何节点上,以便为该节点添加自定义功能。例如,您可以在每次该属性的值更改时,将属性的值打印到 Kanzi Log,或者定义具有可变速度的动画播放。

例如,要创建一个名为 Log Property Value 的自定义节点组件,该组件在该属性的值每次更改时将一个浮点属性类型的值打印到 Kanzi Log:

  1. 在您的 Kanzi Engine 插件项目的 hpp 文件中,包含定义自定义节点组件基类的头文件:

    #include <kanzi/core.ui/node_component/node_component.hpp>
    
  2. 在您的 Kanzi Engine 插件项目的 hpp 文件中,创建表示自定义节点组件的类并定义该节点组件:

    class LogPropertyValueComponent;
    typedef kanzi::shared_ptr<LogPropertyValueComponent> LogPropertyValueComponentSharedPtr;
    
    // Represents the Log Property Value custom node component.
    class LOGPROPERTYVALUECOMPONENT_API LogPropertyValueComponent : public kanzi::NodeComponent
    {
    public:
    
        // The property type that sets which property the Log Property Value custom node component logs.
        static kanzi::PropertyType<kanzi::string> LoggedPropertyTypeProperty;
    
        KZ_METACLASS_BEGIN(LogPropertyValueComponent, NodeComponent, "LogPropertyValueComponent")
            KZ_METACLASS_PROPERTY_TYPE(LoggedPropertyTypeProperty);
        KZ_METACLASS_END()
    
        static kanzi::PropertyTypeEditorInfoSharedPtr makeEditorInfo();
    
        // Creates a LogPropertyValueComponent node component instance.
        static LogPropertyValueComponentSharedPtr create(kanzi::Domain* domain, kanzi::string_view name);
    
    protected:
    
        // The constructor for the LogPropertyValueComponent node component.
        explicit LogPropertyValueComponent(kanzi::Domain* domain, kanzi::string_view name);
    
        void initialize();
    
        // You call the attachOverride() function when the Log Property Value custom node component is attached to the node tree.
        // In the attachOverride() function you get the property type that you want to log and add the notification handler
        // which tracks when the value of that property changes.
        void attachOverride() override;
    
        // You call the detachOverride() function when the Log Property Value custom node component is detached from the node tree.
        // In the detachOverride() function you remove the notification handler which tracks when the value of
        // the property type, which you want to log, changes.
        void detachOverride() override;
    
    ...
    
    };
    
  3. 在表示 Log Property Value 自定义节点组件的类的 hpp 文件中,实现通知处理程序和用于记录属性值的函数:

    // Represents the Log Property Value custom node component.
    class LOGPROPERTYVALUECOMPONENT_API LogPropertyValueComponent : public kanzi::NodeComponent
    {
    
    ...
    
    private:
    
        // The notification handler for the property type that the Log Property Value custom node component logs.
        static void onLoggedPropertyChanged(kanzi::PropertyObject& object, const float& propertyValue,
                                            kanzi::PropertyNotificationReason reason, void* owner);
    
        // Logs a specific property value.
        void logPropertyValue(const float& propertyValue) const;
    
        // The property type that the Log Property Value custom node component logs.
        kanzi::AbstractPropertyType m_loggedPropertyType;
    
    ...
    
    };
    
  4. 在您的 Kanzi Engine 插件项目的 cpp 文件中,添加构造函数和静态 create() 函数,该函数创建节点组件的实例,并定义您在头文件中实现的 NodeComponent::attachOverride 和 NodeComponent::detachOverride 回调函数:

    // Create a Log Property Value custom node component.
    LogPropertyValueComponentSharedPtr LogPropertyValueComponent::create(Domain* domain, string_view name)
    {
        LogPropertyValueComponentSharedPtr component(new LogPropertyValueComponent(domain, name));
    
        component->initialize();
    
        return component;
    }
    
    LogPropertyValueComponent::LogPropertyValueComponent(Domain* domain, string_view name) :
        kanzi::NodeComponent(domain, name)
    {
    }
    
    void LogPropertyValueComponent::initialize()
    {
        // Initialize the base class.
        NodeComponent::initialize();
    }
    
    void LogPropertyValueComponent::attachOverride()
    {
        NodeComponent::attachOverride();
    
        // Get the name of the property type that you want to log.
        const auto loggedPropertyTypeName = getProperty(LoggedPropertyTypeProperty);
        if (loggedPropertyTypeName.empty())
        {
            kzLogInfo(KZ_LOG_CATEGORY_GENERIC, ("Use the Logged Property Type property to set which property type you want to log."));
            return;
        }
    
        // Get the property type that you want to log and check that it is valid.
        const auto loggedPropertyType = AbstractPropertyType(getProperty(LoggedPropertyTypeProperty));
        if (!loggedPropertyType)
        {
            kzLogWarning(KZ_LOG_CATEGORY_GENERIC, ("The custom node component cannot find the property type."));
            return;
        }
        else if (loggedPropertyType.getDataType() != PropertyDataTypeFloat)
        {
            kzLogWarning(KZ_LOG_CATEGORY_GENERIC, ("The custom node component supports property types with float data type."));
            return;
        }
    
        // Add the notification handler for the property type that you want to log.
        const DynamicPropertyType<float> concreteLoggedPropertyType(loggedPropertyType);
        getNode()->addPropertyNotificationHandler(concreteLoggedPropertyType,
                                                   &LogPropertyValueComponent::onLoggedPropertyChanged,
                                                   this);
    
        // Store as a member variable the property type that you want to log.
        m_loggedPropertyType = loggedPropertyType;
    
        // Print the initial value of the property type that you want to log.
        const auto initialPropertyValue = getNode()->getOptionalProperty(concreteLoggedPropertyType);
        if (initialPropertyValue)
        {
            logPropertyValue(*initialPropertyValue);
        }
    }
    
    void LogPropertyValueComponent::detachOverride()
    {
        // Remove the property notification handler for the property that you want to log.
        if (m_loggedPropertyType)
        {
            const DynamicPropertyType<float> concreteLoggedPropertyType(m_loggedPropertyType);
            getNode()->removePropertyNotificationHandler(concreteLoggedPropertyType,
                                                         &LogPropertyValueComponent::onLoggedPropertyChanged,
                                                         this);
        }
        NodeComponent::detachOverride();
    }
    
  5. 在 .cpp 文件中定义您在 .hpp 文件中实现的回调函数,以及用于记录属性类型值的回调函数:

    void LogPropertyValueComponent::onLoggedPropertyChanged(PropertyObject& /*object*/, const float& propertyValue,
                                                            PropertyNotificationReason reason, void* owner)
    {
        // Get the component which receives a notification when the value of
        // the property, which you want to log, changes.
        const auto* component = static_cast<LogPropertyValueComponent*>(owner);
    
        // Kanzi sends a notification each time the value of the property type changes or when that property type is added to a node.
        component->logPropertyValue(propertyValue);
    }
    
    // Use the kzLogInfo logging macro to print:
    // - The name of the node that has a Log Property Value custom node component
    // - The name of the property type that you want to log
    // - The value of that property type
    void LogPropertyValueComponent::logPropertyValue(const float& propertyValue) const
    {
        kzLogInfo(KZ_LOG_CATEGORY_GENERIC, ("{}:{} = {}", getNode()->getName(),
                                            string(m_loggedPropertyType.getName()),
                                            to_string(propertyValue)));
    }
    
  6. 在 cpp 文件中初始化 Logged Property Type 属性类型,并创建 Kanzi Studio 用于 Log Property Value 自定义节点组件的元数据:

    // Declare the metadata for the Logged Property Type property type that you use to set which property
    // the Log Property Value custom node component logs.
    PropertyType<string> LogPropertyValueComponent::LoggedPropertyTypeProperty(kzMakeFixedString("LogPropertyValueComponent.LoggedPropertyType"), "", 0, false,
        KZ_DECLARE_EDITOR_METADATA
        (
            metadata.displayName = "Logged Property Type";
            metadata.tooltip = "The property type whose value you want the node component to log.";
            metadata.valueProvider = "PropertyType";
        ));
    
    // Create the metadata for the Log Property Value custom node component.
    PropertyTypeEditorInfoSharedPtr LogPropertyValueComponent::makeEditorInfo()
    {
        return PropertyTypeEditorInfoSharedPtr(
            KZ_DECLARE_EDITOR_METADATA(
                metadata.displayName = "Log Property Value Component";
                metadata.tooltip = "Writes the value of a specified property to Kanzi Log every time that property changes.";
                metadata.category = "Custom Node Components";
            ));
    }
    
  7. 在 <project_name>_module.cpp 文件中包含提供 Domain 类函数的头文件:

    #include <kanzi/core.ui/domain/domain.hpp>
    
  8. 构建并安装您的 Kanzi Engine 插件。请参阅 将 Kanzi Engine 插件添加到 Kanzi Studio 项目中。。

  9. 在 Kanzi Studio:

    1. 在 Node Tree 中选择您要记录其属性的节点。

    2. 在 Node Components 按 Alt 并右键单击 Custom Node Components 中,选择您创建的 Log Property Value Component 自定义节点组件。

    3. 在 Log Property Value Component 中,将 Logged Property Type 属性设置为您要打印到 Kanzi Log 的属性类型。

      在 Kanzi Studio 中,当您更改该属性的值时,您可以在 Kanzi Studio Log 窗口中看到日志消息。

    ../../_images/create-custom-node-component.png ../../_images/logpropertyvaluecomponent.png ../../_images/kanzi-log-window.png

设置自定义属性类型

要将您在 Kanzi Engine 插件中创建的自定义属性类型信息传递给 Kanzi Studio,您需要声明描述这些属性类型的元数据。

元数据使 Kanzi Engine 插件用户能够在 Kanzi Studio 中与插件内容进行交互。

请参阅 在 Kanzi Studio 中显示 Kanzi Engine 插件自定义类型的参考。。

例如,要为自定义属性类型 VideoFileNameProperty 创建元数据以允许 Kanzi Studio 用户选择视频文件:

PropertyType<string> VideoView2D::VideoFileNameProperty(
    kzMakeFixedString("VideoView2D.VideoFileName"), "video.mp4", 0, false,
    KZ_DECLARE_EDITOR_METADATA(
        // Set the name of the property type the way you want to show it in Kanzi Studio.
        metadata.displayName = "Video Filename";
        // Set the tooltip for the property type.
        metadata.tooltip = "Name of the video file to be played.";
        // Set the category under which this property type is listed in the Properties.
        metadata.category = "Video";
        // Set the editor you want the user to use to edit the value of this property type.
        // BrowseFileTextEditor editor contains a text box with a Browse button next to it.
        metadata.editor = "BrowseFileTextEditor";
        // Set the default value of the property in Kanzi Studio.
        // The Kanzi Engine default value is set in the first line of this example.
        metadata.defaultValue = "video.mp4";
    ));

当用户创建一个 VideoView2D 节点时,Kanzi Studio 会在类别 Video 中向节点的属性添加 Video Filename 属性,该属性具有一个带有 Browse 按钮的文本编辑器、一个工具提示,并且默认值设置为 video.mp4。请参阅 在 Properties 窗口中排列属性类别。

../../_images/video-filename-with-category-and-tooltip.png

属性类型名称不能含有:

  • 属性名称开头或结尾不能使用句点 (.)

  • 空格

  • 制表符

  • 斜线 (/)

  • 反斜杠 ()

  • 井号 (#)

  • 左右大括号 ({})

  • @ 符号

设置属性类型的默认值

在自定义节点中,您可以设置在构建节点时所基于的节点中定义的任何属性类型的默认值。

例如,如果您的节点继承自 Node2D 类,要将 Node::OpacityProperty 属性类型的默认值设置为 0.44,请在您的节点的 makeEditorInfo 中:

PropertyTypeEditorInfoSharedPtr MyNode::makeEditorInfo()
{
    return PropertyTypeEditorInfoSharedPtr(
        KZ_DECLARE_EDITOR_METADATA(
            // Set the default value of the Node.Opacity property to 0.44.
            metadata["override:Node.Opacity:defaultValue"] = "0.44";
            // (Optional) Set how Kanzi Studio suggests the use of this property type.
            // If the "host" value of the property in the base node is:
            // - "auto", you can use "auto" or "fixed"
            // - "context", you can use "auto", "context", "fixed", or "freq"
            // - "fixed", you can use "fixed"
            // - "freq", you can use "auto", "fixed", or "freq"
            // For example, to automatically add the Node.Opacity property
            // when a user adds your node.
            metadata["override:Node.Opacity:host"] = "auto";
        ));
}

请参阅 host。

设置节点类型的图标

如果您没有为节点类型设置图标,Kanzi Studio 将使用默认图标 (image0)。为了让 Kanzi Studio 用户更容易在 Node Tree 中直观地跟踪节点,您可以为节点设置自己的图标。

要为您的节点类型设置自定义图标:

  1. 将您要用于节点的图标放置到 <ProjectName>/Application/src/plugin 目录中。

  2. 在 Kanzi Studio 中,选择 File > Open Kanzi Command Prompt。

    Kanzi Command Prompt 打开 Windows 命令提示符,并为您打开 Kanzi Command Prompt 的 Kanzi 版本设置 Kanzi 环境变量。

    使用 Kanzi Command Prompt 访问 Kanzi 实用工具和构建工具(例如 Gradle 和 CMake),而无需使用绝对路径或设置环境变量。

    ../../_images/open-kanzi-command-prompt.png

    小技巧

    您可以在 Windows 开始菜单的 Rightware 目录中找到 Kanzi Command Prompt。

    当您安装了多个版本的 Kanzi 时,确保将您要在该命令提示符下使用的 Kanzi 版本的 Kanzi Command Prompt 启动。

  3. 在 <ProjectName>/Application 目录中的 Kanzi Command Prompt 中,运行生成应用程序的 Visual Studio 解决方案的脚本。

    generate_cmake_vs2022_solution.bat
    

    此脚本会在 <ProjectName>/Application/build_vs2022 目录中为应用程序生成 Visual Studio 解决方案。

  4. 在 Visual Studio 中,打开您的项目的 <ProjectName>/Application/build_vs<Version>/<ProjectName>.sln Visual Studio 解决方案。

  5. 在解决方案资源管理器中,右键单击 <ProjectName> 项目,选择添加 > 资源,点击导入…,并导入您放置在 <ProjectName>/Application/src/plugin 目录中的 ico 文件。

    ../../_images/vs-add-resource.png ../../_images/vs-import-icon.png
  6. 在 Solution Explorer 中的 <ProjectName> 项目中,双击 <ProjectName>.rc 资源文件以在 Resource View 中打开它。

    ../../_images/vs-plugin-resource-file.png ../../_images/vs-resource-view.png
  7. 在资源视图 (Resource View) 中,从 Icon 目录中选择您导入的图标,并在属性 (Properties) 中将图标资源的 ID 设为您的节点类型的名称,且用引号括起来并全部为大写字母。

    例如,如果您的节点类型是 VideoView2D,请将 ID 设置为 “VIDEOVIEW2D”。

    ../../_images/vs-custom-icon-in-resource-view.png ../../_images/custom-icon-vs-properties.png
  8. 在 Visual Studio 中构建插件,并将插件 DLL 文件复制到之前版本插件所在的相同位置。

    Visual Studio 在 <ProjectName>/Application/lib/<PlatformName>/<ConfigurationName> 和 <ProjectName>/Application/build_vs<Version>/runtime/<ConfigurationName> 目录中构建插件 DLL 文件。

    Kanzi Studio 在 <ProjectName>/Application/lib 目录中使用插件 DLL。

  9. 在 Library > Kanzi Engine Plugins 的 Kanzi Studio 中,右键单击您构建的插件并选择 Update Kanzi Engine Plugin。

    当 Kanzi Studio 加载插件时,它会显示插件中定义的属性和类的更改。

    ../../_images/update-plugin-metadata.png

有关自定义节点类型使用自己图标的示例,请参阅 Node2D 插件示例。

为您的 3D 节点类型创建调试可视化

对于您的 3D 节点类型,您可以创建一个在 Kanzi Studio 中可见的调试可视化,当 Preview 处于 Analyze 模式时。使用调试可视化来渲染在开发插件时有帮助的信息。

要为您的 3D 节点类型创建调试可视化:

  1. 实现您想要在 Preview 中渲染的调试可视化的函数。

  2. 使用 Module::registerDebugRenderingFunctions 函数注册您在插件模块中用于绘制调试可视化的函数。在此函数中,使用 DebugRenderRegistry::addMapping 函数将您的 3D 节点类型映射到绘制调试可视化的函数。

  3. 要在 Kanzi Studio 中查看调试可视化效果,在 Preview 中单击 analyze-off 进入 Analyze 模式,右键单击 分析开启,然后选择 Debug objects。

有关调试可视化的示例,请参阅 Node3D 插件示例。

另请参阅

创建 Kanzi Engine 插件

使用 Kanzi Engine 插件

在 Kanzi Studio 中显示 Kanzi Engine 插件自定义类型的参考。

Node2D 插件示例

Node3D 插件示例

属性系统

创建属性类型