Qt编程:QNodeEditor中的NodeState 类

NodeState 是 QtNodes 框架中负责管理节点连接状态和交互状态的核心类,它跟踪记录节点所有输入/输出连接以及当前的交互状态。

核心职责

  1. 连接管理:维护节点所有输入和输出连接的完整记录

  2. 交互状态跟踪:管理节点对连接操作的响应状态

  3. 数据类型匹配:在连接操作中跟踪涉及的数据类型

  4. 尺寸调整状态:跟踪节点是否正在被调整大小

#pragma once
#include "Export.hpp"
#include "NodeData.hpp"
#include "PortType.hpp"
#include "memory.hpp"

#include <QtCore/QUuid>
#include <unordered_map>
#include <vector>
namespace QtNodes
{
    class Connection;
    class NodeDataModel;
    /// Contains vectors of connected input and output connections.
    /// Stores bool for reacting on hovering connections
    class NODE_EDITOR_PUBLIC NodeState
    {
      public:
        enum ReactToConnectionState
        {
            REACTING,
            NOT_REACTING
        };

      public:
        NodeState(std::unique_ptr<NodeDataModel> const &model);

      public:
        using ConnectionPtrSet = std::unordered_map<QUuid, Connection *>;
        /// Returns vector of connections ID.
        /// Some of them can be empty (null)
        std::vector<ConnectionPtrSet> const &getEntries(PortType) const;
        std::vector<ConnectionPtrSet> &getEntries(PortType);
        ConnectionPtrSet connections(PortType portType, PortIndex portIndex) const;
        void setConnection(PortType portType, PortIndex portIndex, Connection &connection);
        void eraseConnection(PortType portType, PortIndex portIndex, QUuid id);
        ReactToConnectionState reaction() const;
        PortType reactingPortType() const;
        std::shared_ptr<NodeDataType> reactingDataType() const;
        void setReaction(ReactToConnectionState reaction, PortType reactingPortType = PortType::None,
                         std::shared_ptr<NodeDataType> reactingDataType = std::make_shared<NodeDataType>());
        bool isReacting() const;
        void setResizing(bool resizing);
        bool resizing() const;

      private:
        std::vector<ConnectionPtrSet> _inConnections;
        std::vector<ConnectionPtrSet> _outConnections;
        ReactToConnectionState _reaction;
        PortType _reactingPortType;
        std::shared_ptr<NodeDataType> _reactingDataType;
        bool _resizing;
    };
} // namespace QtNodes
#include "NodeState.hpp"

#include "Connection.hpp"
#include "NodeDataModel.hpp"
using QtNodes::Connection;
using QtNodes::NodeDataModel;
using QtNodes::NodeDataType;
using QtNodes::NodeState;
using QtNodes::PortIndex;
using QtNodes::PortType;
NodeState::NodeState(std::unique_ptr<NodeDataModel> const &model)
    : _inConnections(model->nPorts(PortType::In)), _outConnections(model->nPorts(PortType::Out)), _reaction(NOT_REACTING),
      _reactingPortType(PortType::None), _resizing(false)
{
}
std::vector<NodeState::ConnectionPtrSet> const &NodeState::getEntries(PortType portType) const
{
    if (portType == PortType::In)
        return _inConnections;
    else
        return _outConnections;
}
std::vector<NodeState::ConnectionPtrSet> &NodeState::getEntries(PortType portType)
{
    if (portType == PortType::In)
        return _inConnections;
    else
        return _outConnections;
}
NodeState::ConnectionPtrSet NodeState::connections(PortType portType, PortIndex portIndex) const
{
    auto const &connections = getEntries(portType);
    return connections[portIndex];
}
void NodeState::setConnection(PortType portType, PortIndex portIndex, Connection &connection)
{
    auto &connections = getEntries(portType);
    connections.at(portIndex).insert(std::make_pair(connection.id(), &connection));
}
void NodeState::eraseConnection(PortType portType, PortIndex portIndex, QUuid id)
{
    getEntries(portType)[portIndex].erase(id);
}
NodeState::ReactToConnectionState NodeState::reaction() const
{
    return _reaction;
}
PortType NodeState::reactingPortType() const
{
    return _reactingPortType;
}
std::shared_ptr<QtNodes::NodeDataType> NodeState::reactingDataType() const
{
    return _reactingDataType;
}
void NodeState::setReaction(ReactToConnectionState reaction, PortType reactingPortType, std::shared_ptr<NodeDataType> reactingDataType)
{
    _reaction = reaction;
    _reactingPortType = reactingPortType;
    _reactingDataType = std::move(reactingDataType);
}
bool NodeState::isReacting() const
{
    return _reaction == REACTING;
}
bool NodeState::resizing() const
{
    return _resizing;
}

void NodeState::setResizing(bool resizing)
{
    _resizing = resizing;
}

主要数据结构

std::vector<ConnectionPtrSet> _inConnections;   // 输入连接集合
std::vector<ConnectionPtrSet> _outConnections;  // 输出连接集合
ReactToConnectionState _reaction;               // 响应状态
PortType _reactingPortType;                     // 正在交互的端口类型
std::shared_ptr<NodeDataType> _reactingDataType; // 正在交互的数据类型
bool _resizing;                                 // 是否正在调整大小

其中 ConnectionPtrSet 定义为:

std::unordered_map<QUuid, Connection*>  // 连接ID到连接对象的映射

关键方法分析

1. 连接管理方法

// 获取指定端口类型的所有连接
std::vector<ConnectionPtrSet> const& getEntries(PortType) const;
std::vector<ConnectionPtrSet>& getEntries(PortType);

// 获取特定端口的连接集合
ConnectionPtrSet connections(PortType portType, PortIndex portIndex) const;

// 添加连接
void setConnection(PortType portType, PortIndex portIndex, Connection &connection);

// 删除连接
void eraseConnection(PortType portType, PortIndex portIndex, QUuid id);

2. 交互状态管理方法

// 设置/获取响应状态
void setReaction(ReactToConnectionState reaction, 
                PortType reactingPortType = PortType::None,
                std::shared_ptr<NodeDataType> reactingDataType = ...);
ReactToConnectionState reaction() const;

// 检查是否正在响应连接操作
bool isReacting() const;

// 获取正在交互的端口类型
PortType reactingPortType() const;

// 获取正在交互的数据类型
std::shared_ptr<NodeDataType> reactingDataType() const;

3. 尺寸调整状态

// 设置/获取调整大小状态
void setResizing(bool resizing);
bool resizing() const;

设计特点

  1. 双向连接管理:独立维护输入和输出连接集合

  2. 多连接支持:每个端口可以支持多个连接(通过unordered_map实现)

  3. 精确状态跟踪:详细记录交互过程中的端口类型和数据类型

  4. 线程安全考虑:使用智能指针管理数据类型

  5. 高效查找:使用QUuid作为键值实现快速连接查找

与其他类的协作关系

  1. NodeDataModel

    • 初始化时获取端口数量

    • 交互时参考端口连接策略

  2. Connection

    • 存储和管理连接对象

    • 通过QUuid唯一标识连接

  3. Node

    • 作为节点状态的核心管理者

    • 协调状态变化与几何更新

  4. NodeGraphicsObject

    • 响应交互操作时更新状态

    • 调整大小时设置状态标志

状态转换示例

  1. 连接创建过程

    • 用户开始拖拽连接:setReaction(REACTING, PortType::Out, dataType)

    • 用户悬停在目标端口:检查reactingDataType()是否匹配

    • 连接建立:setConnection()添加新连接

    • 完成:setReaction(NOT_REACTING)

  2. 连接删除过程

    • 用户删除连接:eraseConnection()移除指定连接

  3. 调整大小过程

    • 开始调整:setResizing(true)

    • 调整结束:setResizing(false)

使用场景

  1. 绘制节点时

    • 查询连接状态决定如何绘制端口

    • 检查响应状态显示交互反馈

  2. 处理连接操作时

    • 验证连接是否允许

    • 管理连接集合

  3. 执行数据流时

    • 遍历输入连接获取数据

    • 通过输出连接传播数据

  4. 序列化/反序列化时

    • 保存/恢复连接状态

这个类的设计使得节点能够高效地管理复杂的连接关系,并在交互过程中保持精确的状态跟踪,为可视化编程提供了坚实的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值