Qt编程:QtNodeEditor功能概述

【文档】Feature Overview — QtNodes 3.0 documentation

    Qt NodeEditor 是基于 Qt 框架开发的节点编辑器解决方案,非常适合需要嵌入到现有 Qt 应用程序中的图形化编程需求。

功能概述

1. 图形对象ID

      节点(Nodes连接(Connections没有独立的数据实例,所有相关数据均存储在用户自定义的 GraphModel中(需继承 AbstractGraphModel)。

  • 节点ID

    // Definitions.hpp  
    using NodeId = unsigned int;  
  • 每个节点关联唯一的 NodeId,通过 NodeId AbstractGraphModel::addNode(QString) 生成。
    注意GraphModel 需自行保证 NodeId 的唯一性。

  • 连接ID

    struct ConnectionId {
      NodeId    outNodeId;     // 输出节点ID
      PortIndex outPortIndex;  // 输出端口索引
      NodeId    inNodeId;      // 输入节点ID
      PortIndex inPortIndex;   // 输入端口索引
    };

2. 序列化

     当前仅 DataFlowGraphModel 支持序列化。若自定义 AbstractGraphModel 子类,需自行实现序列化逻辑(可参考 src/DataFlowGraphModel.cpp)。

  • 保存场景

    • 遍历所有节点,将数据存入 JSON 的 "nodes" 数组。

    • 遍历所有连接,存入 "connections" 数组。

  • 节点JSON示例

    {
      "id": 0,
      "internal-data": {
        "model-name": "Subtraction"
      },
      "position": {
        "x": -383,
        "y": -95
      }
    }
  • internal-dataDataFlowGraphModel::saveNode(NodeId) 填充,存储节点内部状态(如模型名称)。

  • 连接JSON示例

    {
      "inPortIndex": 0,
      "intNodeId": 1,
      "outNodeId": 0,
      "outPortIndex": 0
    }
  • DataFlowGraphModel::saveConnection 生成。

代码示例
      参考 src/DataFlowGraphModel.cpp 中的 DataFlowGraphModel::save()

3. 撤销/重做(Undo/Redo)

  通过 Qt 的 QUndoStack 实现,默认命令(如 DeleteCommand)已实现在 src/QUndoCommands.cpp

  • 关键点

    • 删除操作会调用 AbstractGraphModel::saveNode()AbstractGraphModel::saveConnection() 保存状态。

    • 自定义模型需重写这两个函数。

4. 自定义图结构封装

  若需可视化自定义图结构(非数据流语义),需继承 AbstractGraphModel 并实现以下功能:

  • 核心机制:类似 Qt 的 QAbstractItemModel,通过 NodeRole 枚举定义节点信息类型:

NodeRole描述数据类型
Type节点类型(如模型名称)QString
Position节点场景坐标QPointF
Size节点内部区域大小QSize
CaptionVisible是否显示标题bool
Caption节点标题文本QString
Style节点样式(颜色、渐变等)QVariantMap
InternalData节点内部状态(序列化为JSON)QVariantMap
InPortCount输入端口数量unsigned int
OutPortCount输出端口数量unsigned int
Widget嵌入节点的控件(无则为 nullptrQWidget*

代码示例
    参考 examples/simple_graph_model

5. 节点与场景样式

    默认样式通过 StyleCollection 管理,从 JSON 字符串解析:

  • 视图样式 (GraphicsViewStyle):

    {
      "BackgroundColor": [53, 53, 53],
      "FineGridColor": [60, 60, 60],
      "CoarseGridColor": [25, 25, 25]
    }
  • 节点样式 (NodeStyle):

    {
      "NormalBoundaryColor": [255, 255, 255],
      "SelectedBoundaryColor": [255, 165, 0],
      "GradientColor0": "gray",
      "ConnectionPointDiameter": 8.0
    }
  • 连接样式 (ConnectionStyle):

    {
      "NormalColor": "darkcyan",
      "SelectedColor": [100, 100, 100],
      "LineWidth": 3.0
    }

代码示例
    参考 examples/stylesexamples/connection_colors

6. 垂直布局(实验性)

    节点端口沿垂直方向排列,布局如下:

 -------o-------------o-------
|  端口标题A      端口标题B   |
|                           |
|        节点标题            |
|                           |
|  端口标题C                 |
 --------------o-------------

代码示例
    参考 examples/vertical_layout

7. 动态端口

    通过 AbstractGraphModel 的以下函数管理:

  • portsAboutToBeInserted / portsInserted

  • portsAboutToBeDeleted / portsDeleted

操作流程

  1. 调用 portsAboutToBeInserted 预计算新端口索引。

  2. 修改底层数据。

  3. 调用 portsInserted 应用变更。

代码示例
    参考 examples/dynamic_ports

8. 锁定节点与连接

  • 锁定节点

    NodeFlags YourGraphModel::nodeFlags(NodeId nodeId) const {
      auto flags = DataFlowGraphModel::nodeFlags(nodeId);
      if (_nodesLocked) flags |= NodeFlag::Locked; // 禁用移动和选择
      return flags;
    }
  • 禁用连接分离
    重写 AbstractGraphModel::detachPossible(ConnectionId) 返回 false

代码示例
    参考 examples/lock_nodes_and_connections

9. 数据传播

    数据流通过 NodeDelegateModel 触发:

  1. 源节点调用 dataUpdated(PortIndex) 发射信号。

  2. DataFlowGraphModel::onOutPortDataUpdated 读取数据并传递给下游节点。

  3. 目标节点通过 NodeDelegateModel::setInData() 接收数据。

信号链

NodeDelegateModel::dataUpdated → DataFlowGraphModel::onOutPortDataUpdated 
→ setPortData → 目标节点setInData

10. 无界面模式(Headless Mode)

  • AbstractGraphModel 可独立于场景使用,直接操作图数据。

  • BasicGraphicsScene 可不绑定 GraphicsView 运行。

代码示例
    参考 examples/calculator/headless_main.cpp,直接加载计算图并执行运算。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值