Qt/C实现的节点式图形编辑器可以添加左侧树上的节点面板可以放大缩小节点之间有输入输出接口使用线进行连接通过鼠标选中节点或线按住delete键可以进行删除可以生成节点的图片进行导出的功能。 源码 使用Qt5.6.1_MinGW、Qt5.13.1_MinGW编译通过其他版本请自行尝试。在某个摸鱼的下午突然想搞点可视化编程的东西于是撸了个能拖拽节点的图形编辑器。核心思路其实挺简单——每个节点都是场景里的可交互元件接口连线本质上是数学坐标系下的路径计算。先看节点类的定义class NodeItem : public QGraphicsItem { public: QRectF boundingRect() const override { return QRectF(-width/2, -height/2, width, height); } void paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) override { // 绘制主体 painter-setBrush(QColor(45, 45, 48)); painter-drawRoundedRect(boundingRect(), 5, 5); // 绘制接口 drawPorts(painter); } private: void drawPorts(QPainter* painter) { const int portRadius 6; QPointF inputPos(-width/2, -portRadius*2); QPointF outputPos(width/2 - portRadius*2, -portRadius*2); painter-setBrush(Qt::cyan); painter-drawEllipse(inputPos, portRadius, portRadius); // 输入口 painter-setBrush(Qt::magenta); painter-drawEllipse(outputPos, portRadius, portRadius); // 输出口 } const int width 120; const int height 80; };这个节点的妙处在于坐标系处理——所有绘制都以节点中心为原点移动时直接用setPos()就能准确定位。接口位置计算用简单算术搞定输入口固定在左侧边缘输出口在右侧后续连线时用scene坐标转换就能获取准确位置。连线功能涉及贝塞尔曲线void ConnectionItem::updatePath() { QPointF start mapFromScene(startPort-scenePos()); QPointF end mapFromScene(endPort-scenePos()); QPainterPath path(start); path.cubicTo( start QPointF(50, 0), // 控制点1 end - QPointF(50, 0), // 控制点2 end ); setPath(path); }这里用了三次贝塞尔曲线让连线看起来自然。控制点的水平偏移量固定为50像素这样无论节点间距多大连线都能呈现平滑的S形。当节点移动时只需要调用updatePath()就能实时更新连线轨迹。Qt/C实现的节点式图形编辑器可以添加左侧树上的节点面板可以放大缩小节点之间有输入输出接口使用线进行连接通过鼠标选中节点或线按住delete键可以进行删除可以生成节点的图片进行导出的功能。 源码 使用Qt5.6.1_MinGW、Qt5.13.1_MinGW编译通过其他版本请自行尝试。删除功能实现得相当暴力void Scene::keyPressEvent(QKeyEvent* event) { if(event-key() Qt::Key_Delete) { foreach(auto item, selectedItems()) { if(auto conn dynamic_castConnectionItem*(item)) { conn-disconnectPorts(); // 先断开端口关联 } delete item; // 直接删除图形项 } } }这里直接捕获场景的键盘事件把选中的元素统统干掉。注意连线删除前要先断开端口关联否则可能出现野指针。这种处理方式虽然简单但胜在直观有效。导出图片就调个现成接口void exportToImage() { QImage image(scene-sceneRect().size().toSize(), QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter painter(image); scene-render(painter); image.save(node_graph.png); }把整个场景渲染到QImage里想存什么格式改后缀就行。不过要注意场景坐标系和图像尺寸的对应关系否则可能导出空白图片。注实测Qt5.6和5.13版本可用其他版本可能需要微调图形项缓存相关的代码
Qt/C++实现的节点式图形编辑器,可以添加左侧树上的节点,面板可以放大缩小,节点之间有输入输...
Qt/C实现的节点式图形编辑器可以添加左侧树上的节点面板可以放大缩小节点之间有输入输出接口使用线进行连接通过鼠标选中节点或线按住delete键可以进行删除可以生成节点的图片进行导出的功能。 源码 使用Qt5.6.1_MinGW、Qt5.13.1_MinGW编译通过其他版本请自行尝试。在某个摸鱼的下午突然想搞点可视化编程的东西于是撸了个能拖拽节点的图形编辑器。核心思路其实挺简单——每个节点都是场景里的可交互元件接口连线本质上是数学坐标系下的路径计算。先看节点类的定义class NodeItem : public QGraphicsItem { public: QRectF boundingRect() const override { return QRectF(-width/2, -height/2, width, height); } void paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) override { // 绘制主体 painter-setBrush(QColor(45, 45, 48)); painter-drawRoundedRect(boundingRect(), 5, 5); // 绘制接口 drawPorts(painter); } private: void drawPorts(QPainter* painter) { const int portRadius 6; QPointF inputPos(-width/2, -portRadius*2); QPointF outputPos(width/2 - portRadius*2, -portRadius*2); painter-setBrush(Qt::cyan); painter-drawEllipse(inputPos, portRadius, portRadius); // 输入口 painter-setBrush(Qt::magenta); painter-drawEllipse(outputPos, portRadius, portRadius); // 输出口 } const int width 120; const int height 80; };这个节点的妙处在于坐标系处理——所有绘制都以节点中心为原点移动时直接用setPos()就能准确定位。接口位置计算用简单算术搞定输入口固定在左侧边缘输出口在右侧后续连线时用scene坐标转换就能获取准确位置。连线功能涉及贝塞尔曲线void ConnectionItem::updatePath() { QPointF start mapFromScene(startPort-scenePos()); QPointF end mapFromScene(endPort-scenePos()); QPainterPath path(start); path.cubicTo( start QPointF(50, 0), // 控制点1 end - QPointF(50, 0), // 控制点2 end ); setPath(path); }这里用了三次贝塞尔曲线让连线看起来自然。控制点的水平偏移量固定为50像素这样无论节点间距多大连线都能呈现平滑的S形。当节点移动时只需要调用updatePath()就能实时更新连线轨迹。Qt/C实现的节点式图形编辑器可以添加左侧树上的节点面板可以放大缩小节点之间有输入输出接口使用线进行连接通过鼠标选中节点或线按住delete键可以进行删除可以生成节点的图片进行导出的功能。 源码 使用Qt5.6.1_MinGW、Qt5.13.1_MinGW编译通过其他版本请自行尝试。删除功能实现得相当暴力void Scene::keyPressEvent(QKeyEvent* event) { if(event-key() Qt::Key_Delete) { foreach(auto item, selectedItems()) { if(auto conn dynamic_castConnectionItem*(item)) { conn-disconnectPorts(); // 先断开端口关联 } delete item; // 直接删除图形项 } } }这里直接捕获场景的键盘事件把选中的元素统统干掉。注意连线删除前要先断开端口关联否则可能出现野指针。这种处理方式虽然简单但胜在直观有效。导出图片就调个现成接口void exportToImage() { QImage image(scene-sceneRect().size().toSize(), QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter painter(image); scene-render(painter); image.save(node_graph.png); }把整个场景渲染到QImage里想存什么格式改后缀就行。不过要注意场景坐标系和图像尺寸的对应关系否则可能导出空白图片。注实测Qt5.6和5.13版本可用其他版本可能需要微调图形项缓存相关的代码