当前位置: 首页 > news >正文

Qt节点编辑器设计与实现:动态编辑与任务流可视化(一)

文章目录

    • 一、项目概述
    • 二、整体架构:模型-视图分离的设计哲学
      • 1. 模型层:数据与业务逻辑的核心
      • 2. 视图层:图形渲染与用户交互
      • 3. 交互层:连接模型与视图的桥梁
    • 三、核心模块解析
      • 1. 样式管理系统:视觉表现的基石
      • 2. 图形数据模型:数据与关系的核心载体
      • 3. 节点交互与几何计算
      • 4. 跨平台与模块化设计
    • 四、实战示例:任务流配置与加载
    • 五、总结

在这里插入图片描述
在这里插入图片描述
Qt节点编辑器设计与实现:动态编辑与任务流可视化(一)
深入解析Qt节点编辑器框架:交互逻辑与样式系统(二)
深入解析Qt节点编辑器框架:数据流转与扩展机制(三)
深入解析Qt节点编辑器框架:高级特性与性能优化(四)

  • 本项目是由Qt开源项目NodeEditor二次开发而来,项目地址,这是个非常不错的项目,熟悉并了解它对自身与Qt画板框架的使用会有很大提升。

一、项目概述

该节点编辑器旨在提供简单易用的任务流可视化编辑功能,支持节点自由布局、动态状态设置与流程连接管理。从代码结构来看,系统采用模块化设计,主要包含样式管理、图形数据模型、节点交互逻辑等核心模块,基于Qt框架实现跨平台兼容,可广泛应用于工作流设计、数据处理流程编排等场景。
包含核心功能如下:

  1. 节点编辑:支持节点的添加、删除、移动、调整大小、动态端口、动态变量等操作。
  2. 连接编辑:支持连接的创建、删除、标签编辑等操作。。
  3. 画板操作:支持撤销、重做、复制、粘贴、旋转、缩放、筛选节点等操作。
  4. 动态样式:支持节点、连接线与画板的动态样式设置,如颜色、字体、边框等。
  5. 菜单栏操作:支持文件操作新建、打开、保存、导出图片等。
  6. 保存与加载:支持将当前任务流保存为文件,后续可加载编辑。
  7. 任务流加载:支持通过通信动态加载节点与连接线,从而达到任务流显示效果。

二、整体架构:模型-视图分离的设计哲学

该框架严格遵循模型-视图(Model-View) 设计模式,将数据逻辑与图形展示解耦,这是处理复杂交互场景的关键。

1. 模型层:数据与业务逻辑的核心

模型层由AbstractGraphModel(抽象基类)和DataFlowGraphModel(具体实现)构成,负责管理节点、连接的核心数据与业务规则:

  • 节点数据:包括节点类型、端口信息、位置尺寸、内部状态等。
  • 连接数据:以ConnectionId(包含源节点、源端口、目标节点、目标端口)唯一标识一条连接,维护连接的有效性规则。
  • 业务逻辑:如连接是否允许创建(类型匹配、无循环)、端口动态增删时的连接调整等。

代码中,DataFlowGraphModel通过_models(存储节点实例)和_connectivity(存储连接ID集合)管理核心数据,对外提供addNodeaddConnection等接口,确保数据操作的一致性。

2. 视图层:图形渲染与用户交互

视图层由BasicGraphicsSceneDataFlowGraphicsScene等场景类,以及NodeGraphicsObjectConnectionGraphicsObject等图形对象类构成:

  • 场景类:继承自QGraphicsScene,负责管理所有图形对象的生命周期,处理全局事件(如右键菜单、保存加载)。
  • 图形对象类:继承自QGraphicsItem,负责单个节点/连接的渲染(如节点样式、连接线条)和局部交互(如拖拽、点击)。

例如,BasicGraphicsScenetraverseGraphAndPopulateGraphicsObjects方法会遍历模型中的节点和连接,创建对应的图形对象,实现模型到视图的初始同步。

3. 交互层:连接模型与视图的桥梁

交互层通过信号槽机制实现模型与视图的实时同步:

  • 模型变化时(如nodeCreatedconnectionDeleted),发送信号通知视图更新图形对象。
  • 视图接收用户操作(如拖拽节点、创建连接),通过命令模式(QUndoStack)修改模型,确保操作可撤销。

代码中,BasicGraphicsScene在构造函数中连接了模型的多个信号(如connectionCreatedonConnectionCreated),保证视图能及时响应模型变化。

三、核心模块解析

1. 样式管理系统:视觉表现的基石

节点编辑器的视觉体验直接影响用户交互效率,该系统通过NodeStyleConnectionStyleStyleCollection构建了灵活的样式管理机制。

  • 多状态样式支持NodeStyle类通过_styleData字典存储不同状态(如正常、选中、错误)的样式配置,包括边界颜色、渐变颜色、阴影效果等。例如,在加载JSON配置时,既支持兼容旧版本的默认样式,也支持多状态样式定义:

    // 多状态样式加载逻辑
    for (auto it = nodeStyleObj.begin(); it != nodeStyleObj.end(); ++it) {QString state = it.key();QJsonObject stateObj = it.value().toObject();NodeStyleData data;// 解析颜色、尺寸等属性..._styleData[state] = data;
    }
    
  • JSON序列化与反序列化:样式配置支持从JSON文件/文本加载,也可导出为JSON,便于配置共享与保存。颜色解析通过parseColor辅助函数实现,支持RGB数组与十六进制字符串两种格式,提升配置灵活性。

  • 全局样式管理StyleCollection作为单例模式,统一管理节点、连接与视图的样式,提供setNodeStyle等方法实现全局样式切换,确保界面风格一致性。

2. 图形数据模型:数据与关系的核心载体

图形数据模型是节点编辑器的"大脑",负责管理节点、连接及其关系。系统通过AbstractGraphModelStandardModelDataFlowGraphModel构建了层次化的模型体系。

  • 节点与连接管理StandardModel实现了节点的增删、连接的创建与删除等基础功能。通过_models存储节点实例,_connectivity维护连接关系,支持allNodeIdsconnections等方法查询数据:

    // 节点添加逻辑
    NodeId StandardModel::addNode(QString const nodeType) {std::unique_ptr<NodeDelegateModel> model = _registry->create(nodeType);if (model) {NodeId newId = newNodeId();_models[newId] = std::move(model);Q_EMIT nodeCreated(newId);return newId;}return InvalidNodeId;
    }
    
  • 动态端口处理:节点端口的动态增删是高级功能,AbstractGraphModel通过portsAboutToBeDeletedportsInserted等方法,在端口变化时自动调整关联连接,避免连接失效:

    // 端口删除前处理关联连接
    void AbstractGraphModel::portsAboutToBeDeleted(...) {for (PortIndex portIndex = first; portIndex <= clampedLast; ++portIndex) {std::unordered_set<ConnectionId> conns = connections(nodeId, portType, portIndex);for (auto connectionId : conns) {deleteConnection(connectionId);}}
    }
    
  • 连接合法性检查DataFlowGraphModel在创建连接时,通过connectionPossible方法检查数据类型匹配、端口是否可用及是否存在循环依赖,确保流程逻辑正确:

    // 无环检查(深度优先遍历)
    auto hasLoops = [this, &connectionId]() -> bool {std::stack<NodeId> filo;filo.push(connectionId.inNodeId);while (!filo.empty()) {auto id = filo.top();filo.pop();if (id == connectionId.outNodeId) return true; // 发现循环// 递归检查下游节点}return false;
    };
    

3. 节点交互与几何计算

节点的交互体验依赖于精准的几何计算,AbstractNodeGeometry类封装了端口位置计算、碰撞检测等核心逻辑:

  • 端口位置计算portScenePosition方法结合节点变换矩阵,计算端口在场景中的绝对位置,为连接绘制提供坐标基础。

  • 端口碰撞检测checkPortHit通过计算鼠标位置与端口的距离,判断是否点击端口,支持用户发起连接操作:

    PortIndex AbstractNodeGeometry::checkPortHit(...) const {double const tolerance = 2.0 * nodeStyle.getNodeStyleData(nodeState).ConnectionPointDiameter;for (unsigned int portIndex = 0; portIndex < n; ++portIndex) {auto pp = portPosition(nodeId, portType, portIndex);QPointF p = pp - nodePoint;auto distance = std::sqrt(QPointF::dotProduct(p, p));if (distance < tolerance) return portIndex;}return InvalidPortIndex;
    }
    

4. 跨平台与模块化设计

系统通过Compiler.hppExport.hpp实现跨平台兼容,支持MinGW、Clang、MSVC等主流编译器,并通过宏定义统一动态库导出/导入逻辑:

// 跨平台导出宏定义
#ifdef NODE_EDITOR_PLATFORM_WINDOWS
#define NODE_EDITOR_EXPORT __declspec(dllexport)
#define NODE_EDITOR_IMPORT __declspec(dllimport)
#elif NODE_EDITOR_COMPILER_GNU_VERSION_MAJOR >=4 || defined(NODE_EDITOR_COMPILER_CLANG)
#define NODE_EDITOR_EXPORT __attribute__((visibility("default")))
#endif

节点数据处理采用模块化设计,MathOperationDataModelDecimalData展示了如何实现具体节点逻辑(如数值计算),通过setInData接收输入、compute处理数据、outData输出结果,便于扩展新节点类型。

四、实战示例:任务流配置与加载

MainWidget中的test方法展示了如何通过JSON配置初始化任务流,这是我随意模拟的数据,实际上的数据应该是通信数据解析而来。示例JSON包含节点(如"星期一"、“上班”)与连接关系,加载后通过定时器动态更新数据,模拟任务流的运行状态:

// 从JSON字符串加载任务流
QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8());
m_jsonObj = doc.object();
// 定时器更新数据
m_testTimer->start(1000);

五、总结

  • 本身也就是为了学习更加深入的Qt画板框架,所以项目开源
  • 节点编辑器框架的设计与实现,从基础到高级,覆盖了模型-视图分离、交互逻辑、数据流转、扩展机制等多个方面。
  • 框架的核心技术点包括模型-视图分离、命令模式、信号槽机制、类型安全的传递机制、依赖驱动的更新逻辑、惰性计算、抽象接口与工厂模式、序列化等。
  • 框架的优势在于其高度的可定制性、可扩展性、可维护性。
  • 框架的应用场景包括可视化编程、数据处理流水线、工业控制流程图等。
  • 未来可进一步优化的方向包括分布式节点计算(跨进程/网络)、节点性能分析工具、AI辅助节点推荐等。
http://www.dtcms.com/a/356448.html

相关文章:

  • WebStorm-在WebStorm中使用Git管理项目
  • 【WPF】WPF 自定义控件实战:从零打造一个可复用的 StatusIconTextButton (含避坑指南)
  • 循环高级(2)
  • 面试八股文之——JVM与并发编程/多线程
  • Azure、RDP、NTLM 均现高危漏洞,微软发布2025年8月安全更新
  • 【物联网】什么是 DHT11(数字温湿度传感器)?
  • C++ 编译和运行 LibCurl 动态库和静态库
  • SyncBack 备份同步软件: 使用 FTPS、SFTP 和 HTTPS 安全加密传输文件
  • 【2025 完美解决】Failed connect to github.com:443; Connection timed out
  • 网络编程(2)—多客户端交互
  • 跨境物流新引擎:亚马逊AGL空运服务赋能卖家全链路升级
  • Pycharm 登录 Github 失败
  • idea2023.3遇到了Lombok失效问题,注释optional和annotationProcessorPaths即可恢复正常
  • “FAQ + AI”智能助手全栈实现方案
  • 极飞科技AI智慧农业实践:3000亩棉田2人管理+产量提15%,精准灌溉与老农操作门槛引讨论
  • autojs RSA加密(使用public.pem、private.pem)
  • 【拍摄学习记录】03-曝光
  • Lora与QLora
  • 创维E910V10C_晶晨S905L2和S905L3芯片_线刷固件包
  • SpringMVC相关梳理
  • 第三方软件测试:【深度解析SQL注入攻击原理和防御原理】
  • [Mysql数据库] 知识点总结6
  • 《Linux 网络编程六:数据存储与SQLite应用指南》
  • LabVIEW转速仪校准系统
  • uniapp跨平台开发---uni.request返回int数字过长精度丢失
  • uni-app + Vue3 开发H5 页面播放海康ws(Websocket协议)的视频流
  • 学习:uniapp全栈微信小程序vue3后台(6)
  • Uniapp + UView + FastAdmin 性格测试小程序方案
  • 2025最新uni-app横屏适配方案:微信小程序全平台兼容实战
  • 项目一系列-第9章 集成AI千帆大模型