Qt编程:QNodeEditor中的Node类

Node 类是 QtNodes 框架中的核心类之一,代表流程图中的一个节点。它负责管理节点的数据模型、图形表示、状态和连接关系。

主要功能

  1. 节点管理:创建、保存和恢复节点

  2. 数据传播:处理节点间的数据流动

  3. 图形表示:管理节点的可视化部分

  4. 连接处理:管理与该节点相关的连接

#pragma once
#include "ConnectionGraphicsObject.hpp"
#include "Export.hpp"
#include "NodeData.hpp"
#include "NodeGeometry.hpp"
#include "NodeGraphicsObject.hpp"
#include "NodeState.hpp"
#include "PortType.hpp"
#include "Serializable.hpp"
#include "memory.hpp"

#include <QtCore/QJsonObject>
#include <QtCore/QObject>
#include <QtCore/QUuid>
namespace QtNodes
{
    class Connection;
    class ConnectionState;
    class NodeGraphicsObject;
    class NodeDataModel;
    class NODE_EDITOR_PUBLIC Node
        : public QObject
        , public Serializable
    {
        Q_OBJECT
      public:
        /// NodeDataModel should be an rvalue and is moved into the Node
        Node(std::unique_ptr<NodeDataModel> &&dataModel);
        virtual ~Node();

      public:
        QJsonObject save() const override;
        void restore(QJsonObject const &json) override;

      public:
        QUuid id() const;
        void reactToPossibleConnection(PortType, std::shared_ptr<NodeDataType>, QPointF const &scenePoint);
        void resetReactionToConnection();

      public:
        NodeGraphicsObject const &nodeGraphicsObject() const;
        NodeGraphicsObject &nodeGraphicsObject();
        void setGraphicsObject(std::unique_ptr<NodeGraphicsObject> &&graphics);
        NodeGeometry &nodeGeometry();
        NodeGeometry const &nodeGeometry() const;
        NodeState const &nodeState() const;
        NodeState &nodeState();
        NodeDataModel *nodeDataModel() const;
      public Q_SLOTS: // data propagation
        /// Propagates incoming data to the underlying model.
        void propagateData(PortIndex inPortIndex) const;
        /// Fetches data from model's OUT #index port
        /// and propagates it to the connection
        void onDataUpdated(PortIndex index);
        /// update the graphic part if the size of the embeddedwidget changes
        void onNodeSizeUpdated();

      private:
        // addressing
        QUuid _uid;
        // data
        std::unique_ptr<NodeDataModel> _nodeDataModel;
        NodeState _nodeState;
        // painting
        NodeGeometry _nodeGeometry;
        std::unique_ptr<NodeGraphicsObject> _nodeGraphicsObject;
    };
} // namespace QtNodes
#include "Node.hpp"

#include "ConnectionGraphicsObject.hpp"
#include "ConnectionState.hpp"
#include "FlowScene.hpp"
#include "NodeDataModel.hpp"
#include "NodeGraphicsObject.hpp"

#include <QtCore/QObject>
#include <iostream>
#include <utility>
using QtNodes::Node;
using QtNodes::NodeData;
using QtNodes::NodeDataModel;
using QtNodes::NodeDataType;
using QtNodes::NodeGeometry;
using QtNodes::NodeGraphicsObject;
using QtNodes::NodeState;
using QtNodes::PortIndex;
using QtNodes::PortType;
Node::Node(std::unique_ptr<NodeDataModel> &&dataModel)
    : _uid(QUuid::createUuid()), _nodeDataModel(std::move(dataModel)), _nodeState(_nodeDataModel), _nodeGeometry(_nodeDataModel),
      _nodeGraphicsObject(nullptr)
{
    _nodeGeometry.recalculateSize();
    // propagate data: model => node
    connect(_nodeDataModel.get(), &NodeDataModel::dataUpdated, this, &Node::onDataUpdated);
    connect(_nodeDataModel.get(), &NodeDataModel::embeddedWidgetSizeUpdated, this, &Node::onNodeSizeUpdated);
}
Node::~Node() = default;
QJsonObject Node::save() const
{
    QJsonObject nodeJson;
    nodeJson["id"] = _uid.toString();
    nodeJson["model"] = _nodeDataModel->save();
    QJsonObject obj;
    obj["x"] = _nodeGraphicsObject->pos().x();
    obj["y"] = _nodeGraphicsObject->pos().y();
    nodeJson["position"] = obj;
    return nodeJson;
}
void Node::restore(QJsonObject const &json)
{
    _uid = QUuid(json["id"].toString());
    QJsonObject positionJson = json["position"].toObject();
    QPointF point(positionJson["x"].toDouble(), positionJson["y"].toDouble());
    _nodeGraphicsObject->setPos(point);
    _nodeDataModel->restore(json["model"].toObject());
}
QUuid Node::id() const
{
    return _uid;
}
void Node::reactToPossibleConnection(PortType reactingPortType, std::shared_ptr<NodeDataType> reactingDataType, QPointF const &scenePoint)
{
    QTransform const t = _nodeGraphicsObject->sceneTransform();
    QPointF nodePoint = t.inverted().map(scenePoint);
    _nodeGeometry.setDraggingPosition(nodePoint);
    _nodeGraphicsObject->update();
    _nodeState.setReaction(NodeState::REACTING, reactingPortType, reactingDataType);
}
void Node::resetReactionToConnection()
{
    _nodeState.setReaction(NodeState::NOT_REACTING);
    _nodeGraphicsObject->update();
}
NodeGraphicsObject const &Node::nodeGraphicsObject() const
{
    return *_nodeGraphicsObject.get();
}
NodeGraphicsObject &Node::nodeGraphicsObject()
{
    return *_nodeGraphicsObject.get();
}
void Node::setGraphicsObject(std::unique_ptr<NodeGraphicsObject> &&graphics)
{
    _nodeGraphicsObject = std::move(graphics);
    _nodeGeometry.recalculateSize();
}
NodeGeometry &Node::nodeGeometry()
{
    return _nodeGeometry;
}
NodeGeometry const &Node::nodeGeometry() const
{
    return _nodeGeometry;
}
NodeState const &Node::nodeState() const
{
    return _nodeState;
}
NodeState &Node::nodeState()
{
    return _nodeState;
}
NodeDataModel *Node::nodeDataModel() const
{
    return _nodeDataModel.get();
}
void Node::propagateData(PortIndex inPortIndex) const
{
    NodeState const &state = nodeState();
    NodeState::ConnectionPtrSet connections = state.connections(PortType::In, inPortIndex);
    std::vector<std::shared_ptr<NodeData>> nodeData;
    nodeData.reserve(connections.size());
    for (const auto &connection : connections)
    {
        Connection *c = connection.second;
        Node *outNode = c->getNode(PortType::Out);
        PortIndex outNodeIndex = c->getPortIndex(PortType::Out);
        std::shared_ptr<NodeData> outData = outNode->nodeDataModel()->outData(outNodeIndex);
        TypeConverter converter = c->getTypeConverter();
        if (converter != nullptr)
        {
            outData = converter(outData);
        }
        nodeData.push_back(outData);
    }
    _nodeDataModel->setInData(std::move(nodeData), inPortIndex);
    // Recalculate the nodes visuals. A data change can result in the node taking
    // more space than before, so this forces a recalculate+repaint on the affected
    // node
    _nodeGraphicsObject->setGeometryChanged();
    _nodeGeometry.recalculateSize();
    _nodeGraphicsObject->update();
    _nodeGraphicsObject->moveConnections();
}
void Node::onDataUpdated(PortIndex index)
{
    auto connections = _nodeState.connections(PortType::Out, index);
    for (auto const &c : connections) c.second->propagateData();
}
void Node::onNodeSizeUpdated()
{
    if (nodeDataModel()->embeddedWidget())
    {
        nodeDataModel()->embeddedWidget()->adjustSize();
    }
    nodeGeometry().recalculateSize();
    for (PortType type : { PortType::In, PortType::Out })
    {
        for (auto &conn_set : nodeState().getEntries(type))
        {
            for (auto &pair : conn_set)
            {
                Connection *conn = pair.second;
                conn->getConnectionGraphicsObject().move();
            }
        }
    }
}

类成员详解

构造函数

Node(std::unique_ptr<NodeDataModel> &&dataModel)
  • 使用给定的 NodeDataModel 创建一个新节点

  • 自动生成唯一 ID (QUuid)

  • 初始化节点状态、几何信息和图形对象

  • 设置数据模型信号与节点槽的连接

序列化方法

QJsonObject save() const override
void restore(QJsonObject const &json) override
  • save(): 将节点状态保存为 JSON 对象,包括 ID、模型数据和位置

  • restore(): 从 JSON 对象恢复节点状态

节点标识

QUuid id() const
  • 返回节点的唯一标识符

连接反应处理

void reactToPossibleConnection(PortType, std::shared_ptr<NodeDataType>, QPointF const &scenePoint)
void resetReactionToConnection()
  • 处理可能的连接操作时的视觉反馈

  • 重置连接反应状态

访问器方法

// 图形对象访问
NodeGraphicsObject const &nodeGraphicsObject() const
NodeGraphicsObject &nodeGraphicsObject()
void setGraphicsObject(std::unique_ptr<NodeGraphicsObject> &&graphics)

// 几何信息访问
NodeGeometry &nodeGeometry()
NodeGeometry const &nodeGeometry() const

// 状态访问
NodeState const &nodeState() const
NodeState &nodeState()

// 数据模型访问
NodeDataModel *nodeDataModel() const

数据传播槽

void propagateData(PortIndex inPortIndex) const
void onDataUpdated(PortIndex index)
void onNodeSizeUpdated()
  • propagateData(): 将输入端口的数据传播到模型

  • onDataUpdated(): 当模型数据更新时通知连接的连接

  • onNodeSizeUpdated(): 当节点大小变化时更新几何信息和连接位置

内部实现细节

数据成员

  • _uid: 节点的唯一标识符

  • _nodeDataModel: 节点数据模型的唯一指针

  • _nodeState: 节点状态对象,管理连接状态

  • _nodeGeometry: 节点几何信息对象

  • _nodeGraphicsObject: 节点图形对象的唯一指针

数据传播机制

propagateData() 方法实现了从输入连接获取数据并传递给模型的核心逻辑:

  1. 获取指定输入端口的连接集合

  2. 从每个连接的输出节点获取数据

  3. 应用类型转换器(如果有)

  4. 将数据集合传递给模型的 setInData() 方法

  5. 更新节点的视觉表示

使用场景

  1. 创建新节点:通过传入数据模型创建节点

  2. 保存/加载流程图:使用序列化方法保存和恢复节点状态

  3. 处理用户交互:通过图形对象处理鼠标事件

  4. 数据流处理:当连接建立或数据更新时自动传播数据

与其他类的关系

  • NodeDataModel: 包含节点的业务逻辑和数据

  • NodeGraphicsObject: 处理节点的可视化表示

  • NodeGeometry: 管理节点的几何信息

  • NodeState: 跟踪节点的连接状态

  • Connection: 表示节点间的连接关系

Node 类作为这些组件的协调者,将它们整合为一个完整的节点功能单元。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值