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

文章目录

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



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

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

一、项目概述

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

包含核心功能如下:

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

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

该框架严格遵循模型-视图(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配置时,既支持兼容旧版本的默认样式,也支持多状态样式定义:

    cpp 复制代码
    // 多状态样式加载逻辑
    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等方法查询数据:

    cpp 复制代码
    // 节点添加逻辑
    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等方法,在端口变化时自动调整关联连接,避免连接失效:

    cpp 复制代码
    // 端口删除前处理关联连接
    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方法检查数据类型匹配、端口是否可用及是否存在循环依赖,确保流程逻辑正确:

    cpp 复制代码
    // 无环检查(深度优先遍历)
    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通过计算鼠标位置与端口的距离,判断是否点击端口,支持用户发起连接操作:

    cpp 复制代码
    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等主流编译器,并通过宏定义统一动态库导出/导入逻辑:

cpp 复制代码
// 跨平台导出宏定义
#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包含节点(如"星期一"、"上班")与连接关系,加载后通过定时器动态更新数据,模拟任务流的运行状态:

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

五、总结

  • 本身也就是为了学习更加深入的Qt画板框架,所以项目开源
  • 节点编辑器框架的设计与实现,从基础到高级,覆盖了模型-视图分离、交互逻辑、数据流转、扩展机制等多个方面。
  • 框架的核心技术点包括模型-视图分离、命令模式、信号槽机制、类型安全的传递机制、依赖驱动的更新逻辑、惰性计算、抽象接口与工厂模式、序列化等。
  • 框架的优势在于其高度的可定制性、可扩展性、可维护性。
  • 框架的应用场景包括可视化编程、数据处理流水线、工业控制流程图等。
  • 未来可进一步优化的方向包括分布式节点计算(跨进程/网络)、节点性能分析工具、AI辅助节点推荐等。
相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript