Qt编程:QNodeEditor中的DataModelRegistry 类

DataModelRegistry 是 QtNodes 框架中的模型注册中心,负责管理所有可用的节点数据模型和类型转换器。

核心职责

  1. 节点模型注册与管理:维护所有可用的节点数据模型

  2. 分类管理:将模型按类别组织

  3. 模型实例创建:根据名称创建模型实例

  4. 类型转换器管理:注册和查找数据类型转换器

#pragma once
#include "Export.hpp"
#include "NodeDataModel.hpp"
#include "QStringStdHash.hpp"
#include "TypeConverter.hpp"
#include "memory.hpp"

#include <QtCore/QString>
#include <functional>
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
namespace QtNodes
{
    /// Class uses map for storing models (name, model)
    class NODE_EDITOR_PUBLIC DataModelRegistry
    {
      public:
        using RegistryItemPtr = std::unique_ptr<NodeDataModel>;
        using RegistryItemCreator = std::function<RegistryItemPtr()>;
        using RegisteredModelCreatorsMap = std::unordered_map<QString, RegistryItemCreator>;
        using RegisteredModelsCategoryMap = std::unordered_map<QString, QString>;
        using CategoriesSet = std::set<QString>;
        using RegisteredTypeConvertersMap = std::map<TypeConverterId, TypeConverter>;
        DataModelRegistry() = default;
        ~DataModelRegistry() = default;
        DataModelRegistry(DataModelRegistry const &) = delete;
        DataModelRegistry(DataModelRegistry &&) = default;
        DataModelRegistry &operator=(DataModelRegistry const &) = delete;
        DataModelRegistry &operator=(DataModelRegistry &&) = default;

      public:
        template<typename ModelType>
        void registerModel(RegistryItemCreator creator, QString const &category = "Nodes")
        {
            registerModelImpl<ModelType>(std::move(creator), category);
        }
        template<typename ModelType>
        void registerModel(QString const &category = "Nodes")
        {
            RegistryItemCreator creator = []() {
                return std::make_unique<ModelType>();
            };
            registerModelImpl<ModelType>(std::move(creator), category);
        }
        template<typename ModelType>
        void registerModel(QString const &category, RegistryItemCreator creator)
        {
            registerModelImpl<ModelType>(std::move(creator), category);
        }
        void registerTypeConverter(TypeConverterId const &id, TypeConverter typeConverter)
        {
            _registeredTypeConverters[id] = std::move(typeConverter);
        }
        std::unique_ptr<NodeDataModel> create(QString const &modelName);
        RegisteredModelCreatorsMap const &registeredModelCreators() const;
        RegisteredModelsCategoryMap const &registeredModelsCategoryAssociation() const;
        CategoriesSet const &categories() const;
        TypeConverter getTypeConverter(NodeDataTypeId const &d1, NodeDataTypeId const &d2) const;

      private:
        RegisteredModelsCategoryMap _registeredModelsCategory;
        CategoriesSet _categories;
        RegisteredModelCreatorsMap _registeredItemCreators;
        RegisteredTypeConvertersMap _registeredTypeConverters;

      private:
        // If the registered ModelType class has the static member method
        //
        //      static Qstring Name();
        //
        // use it. Otherwise use the non-static method:
        //
        //       virtual QString name() const;
        template<typename T, typename = void>
        struct HasStaticMethodName : std::false_type
        {
        };
        template<typename T>
        struct HasStaticMethodName<T, typename std::enable_if<std::is_same<decltype(T::Name()), QString>::value>::type> : std::true_type
        {
        };
        template<typename ModelType>
        typename std::enable_if<HasStaticMethodName<ModelType>::value>::type registerModelImpl(RegistryItemCreator creator,
                                                                                               QString const &category)
        {
            const QString name = ModelType::Name();
            if (_registeredItemCreators.count(name) == 0)
            {
                _registeredItemCreators[name] = std::move(creator);
                _categories.insert(category);
                _registeredModelsCategory[name] = category;
            }
        }
        template<typename ModelType>
        typename std::enable_if<!HasStaticMethodName<ModelType>::value>::type registerModelImpl(RegistryItemCreator creator,
                                                                                                QString const &category)
        {
            const QString name = creator()->name();
            if (_registeredItemCreators.count(name) == 0)
            {
                _registeredItemCreators[name] = std::move(creator);
                _categories.insert(category);
                _registeredModelsCategory[name] = category;
            }
        }
    };
} // namespace QtNodes
#include "DataModelRegistry.hpp"

#include <QtCore/QFile>
#include <QtWidgets/QMessageBox>
using QtNodes::DataModelRegistry;
using QtNodes::NodeDataModel;
using QtNodes::NodeDataType;
using QtNodes::TypeConverter;
std::unique_ptr<NodeDataModel> DataModelRegistry::create(QString const &modelName)
{
    auto it = _registeredItemCreators.find(modelName);
    if (it != _registeredItemCreators.end())
    {
        return it->second();
    }
    return nullptr;
}
DataModelRegistry::RegisteredModelCreatorsMap const &DataModelRegistry::registeredModelCreators() const
{
    return _registeredItemCreators;
}
DataModelRegistry::RegisteredModelsCategoryMap const &DataModelRegistry::registeredModelsCategoryAssociation() const
{
    return _registeredModelsCategory;
}
DataModelRegistry::CategoriesSet const &DataModelRegistry::categories() const
{
    return _categories;
}
TypeConverter DataModelRegistry::getTypeConverter(QtNodes::NodeDataTypeId const &d1, QtNodes::NodeDataTypeId const &d2) const
{
    TypeConverterId converterId = std::make_pair(d1, d2);
    auto it = _registeredTypeConverters.find(converterId);
    if (it != _registeredTypeConverters.end())
    {
        return it->second;
    }
    return TypeConverter{};
}

类成员详解

关键类型定义

using RegistryItemPtr = std::unique_ptr<NodeDataModel>;  // 模型指针类型
using RegistryItemCreator = std::function<RegistryItemPtr()>;  // 模型创建函数
using RegisteredModelCreatorsMap = std::unordered_map<QString, RegistryItemCreator>;  // 模型创建器映射
using RegisteredModelsCategoryMap = std::unordered_map<QString, QString>;  // 模型-类别映射
using CategoriesSet = std::set<QString>;  // 类别集合
using RegisteredTypeConvertersMap = std::map<TypeConverterId, TypeConverter>;  // 类型转换器映射

注册方法

模型注册

// 三种重载形式
template<typename ModelType>
void registerModel(RegistryItemCreator creator, QString const &category = "Nodes");

template<typename ModelType>
void registerModel(QString const &category = "Nodes");

template<typename ModelType>
void registerModel(QString const &category, RegistryItemCreator creator);
  • 支持自定义创建函数或使用默认构造函数

  • 可指定模型所属类别(默认为"Nodes")

  • 自动检测模型是否有静态Name()方法

类型转换器注册

void registerTypeConverter(TypeConverterId const &id, TypeConverter typeConverter);

查询方法

std::unique_ptr<NodeDataModel> create(QString const &modelName);  // 创建模型实例
RegisteredModelCreatorsMap const &registeredModelCreators() const;  // 获取所有模型创建器
RegisteredModelsCategoryMap const &registeredModelsCategoryAssociation() const;  // 获取模型-类别映射
CategoriesSet const &categories() const;  // 获取所有类别
TypeConverter getTypeConverter(NodeDataTypeId const &d1, NodeDataTypeId const &d2) const;  // 获取类型转换器

内部实现细节

SFINAE 检测静态 Name() 方法

template<typename T, typename = void>
struct HasStaticMethodName : std::false_type {};

template<typename T>
struct HasStaticMethodName<T, typename std::enable_if<std::is_same<decltype(T::Name()), QString>::value>::type> 
    : std::true_type {};

// 根据是否有静态Name()方法选择不同实现
template<typename ModelType>
typename std::enable_if<HasStaticMethodName<ModelType>::value>::type 
registerModelImpl(RegistryItemCreator creator, QString const &category);

template<typename ModelType>
typename std::enable_if<!HasStaticMethodName<ModelType>::value>::type 
registerModelImpl(RegistryItemCreator creator, QString const &category);

使用示例

注册模型

registry.registerModel<MyNodeModel>("Custom Nodes");

注册带自定义创建的模型

registry.registerModel<MyNodeModel>(
    "Custom Nodes",
    []() { return std::make_unique<MyNodeModel>(param1, param2); }
);

创建模型实例

auto model = registry.create("MyNodeModel");

注册类型转换器

registry.registerTypeConverter(
    {sourceType.id(), targetType.id()},
    [](std::shared_ptr<NodeData> data) {
        // 转换逻辑
        return std::make_shared<TargetType>(...);
    }
);

设计特点

  1. 灵活注册:支持多种模型注册方式

  2. 类型安全:使用模板确保模型类型正确

  3. 自动检测:智能检测模型的命名方式

  4. 分类管理:方便UI按类别展示模型

  5. 扩展性强:易于添加新的模型和转换器

典型应用场景

  1. 初始化注册:在应用启动时注册所有可用模型

  2. 插件系统:动态加载和注册模型

  3. 模型选择器:提供可用的模型列表供用户选择

  4. 类型转换:处理不同类型节点间的数据连接

这个注册中心是 QtNodes 框架可扩展性的关键,使得添加新节点类型变得简单而规范。

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值