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

开源节点框架STNodeEditor使用

节点,一般都为树形Tree结构,如TreeNode,XmlNode。

树形结构有其关键属性Parent【父节点】,Children【子节点】

LinkedListNode为链表线性结构,有其关键属性Next【下一个】,Previous【上一个】,

可以用其进行工作流workFlow设计

右键 项目 STNodeDemo,管理NuGet程序包

输入关键字STNodeEditor

安装完成后

我们可以查看工具箱

开源的 .NET 轻量级且功能强大的节点编辑器STNodeEditor

STNodeEditor 是一个轻量且功能强大的节点编辑器 使用方式非常简洁 提供了丰富的属性以及事件可以非常方便的完成节点之间数据的交互及通知 大量的虚函数可供开发者重写具有很高的自由性。

当有很多应用程序(模块) 它们之间需要相互调用传递数据来完成一整套流程的工作 开发单一功能的应用程序(模块)相对比较容易 而实现一整套很多功能相互调用的应用程序相对比较繁琐 此套框架开发者只需要定义好传递的数据类型 然后分别实现单一节点功能 至于执行流程交给框架和用户布线即可。

项目地址

https://github.com/DebugST/STNodeEditor

STNodeEditor是基于WinForm的一套框架 使用GDI+开发 不包含任何额外依赖 整个调用库仅100+kb 

项目主页:https://debugst.github.io/STNodeEditor/

教程文档:https://debugst.github.io/STNodeEditor/doc_cn.html 

NuGet:https://www.nuget.org/packages/ST.Library.UI/

GitHub:https://github.com/DebugST/STNodeEditor 

由上图可见 STNodeEditor 包含3部分 TreeView PropertyGrid NodeEditor 这三部分组成了一套完整的可使用框架

TreeView
开发这可以把执行功能编码到一个节点中 而TreeView则负责展示以及检索节点 在TreeView中的节点可直接拖拽添加到NodeEditor中
PropertyGrid
类似与WinForm开发使用的属性窗口 作为一个节点 它也是可以有属性的 而作者在编辑器进行设计的过程中也把一个节点视作一个Form让开发者几乎没有什么学习成本直接上手一个节点的开发
NodeEditor
NodeEditor是用户组合自己执行流程的地方 使得功能模块执行流程可视化
 

因ST.Library.UI.NodeEditor.STNode 是一个抽象类,因此我们需要新建一个子类SnakeNode 

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ST.Library.UI.NodeEditor;namespace STNodeDemo
{public class SnakeNode : ST.Library.UI.NodeEditor.STNode{public SnakeNode(string title) {this.Title = title;this.TitleColor = Color.FromArgb(200, Color.Goldenrod);}/// <summary>/// 输出节点集合/// </summary>public List<STNodeOption> OutputOptionCollection = new List<STNodeOption>();STNodeOption outputTest;protected override void OnCreate(){base.OnCreate();this.Title = "SnakeNode";//输入项集合int index = this.InputOptions.Add(new STNodeOption("Input1", typeof(string), false));STNodeOption nodeIn2 = this.InputOptions.Add("Input2", typeof(int), false);STNodeOption nodeIn3 = this.InputOptions.Add("Input3", typeof(float), false);//输出项集合STNodeOption nodeOut = this.OutputOptions.Add("Output1", typeof(string), false);outputTest = this.OutputOptions.Add("OutputTime", typeof(DateTime), false);OutputOptionCollection.Add(nodeOut);OutputOptionCollection.Add(outputTest);//STNodeOption[] ss = this.GetOutputOptions();}//当所有者发生改变(即:在NodeEditor中被添加或移除)//应当像容器提交自己拥有数据类型的连接点 所期望显示的颜色//颜色主要用于区分不同的数据类型protected override void OnOwnerChanged(){base.OnOwnerChanged();if (this.Owner == null) return;this.Owner.SetTypeColor(typeof(string), Color.Yellow);//当前容器中已有的颜色会被替换this.Owner.SetTypeColor(typeof(int), Color.DodgerBlue, true);this.Owner.SetTypeColor(typeof(float), Color.Pink, true);this.Owner.SetTypeColor(typeof(DateTime), Color.Green, true);//下面的代码将忽略容器中已有的颜色//this.SetOptionDotColor(op, Color.Red); //无需在OnOwnerChanged()中设置Task.Factory.StartNew(() => {for (int i = 0; i < 50; i++){System.Threading.Thread.Sleep(1000);//STNodeOption.TransferData(object)会自动设置STNodeOption.Data//然后自动向所有连接的选项进行数据传递outputTest.TransferData(DateTime.Now);}});}}
}

新建测试接收节点类ViperNode

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ST.Library.UI.NodeEditor;namespace STNodeDemo
{public class ViperNode : ST.Library.UI.NodeEditor.STNode{public ViperNode(string title) {this.Title = title;this.TitleColor = Color.FromArgb(200, Color.Goldenrod);}/// <summary>/// 输入节点集合/// </summary>public List<STNodeOption> InputOptionCollection = new List<STNodeOption>();STNodeOption inputTest;protected override void OnCreate(){base.OnCreate();this.Title = "ViperNode";//输入项集合inputTest = this.InputOptions.Add("ViperTime", typeof(DateTime), false);inputTest.DataTransfer += new STNodeOptionEventHandler(InputTest_DataTransfer);InputOptionCollection.Add(inputTest);}private void InputTest_DataTransfer(object sender, STNodeOptionEventArgs e){//当连接的建立与断开都会触发此事件 所以需要判断连接状态if (e.Status != ConnectionStatus.Connected || e.TargetOption.Data == null){//当 STNode.AutoSize=true 并不建议使用STNode.SetOptionText//因为当文本发生改变时候会重新计算布局 正确的做法是自定义一个如Lable控件//作为时间的显示 当然这里为了演示方式采用此方案this.SetOptionText(inputTest, "--");}else{this.SetOptionText(inputTest, Convert.ToDateTime(e.TargetOption.Data).ToString("yyyy-MM-dd HH:mm:ss.fff"));}}}
}

新建测试窗体FormSTNode,设计如下

FormSTNode.Designer.cs设计器代码如下:


namespace STNodeDemo
{partial class FormSTNode{/// <summary>/// 必需的设计器变量。/// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// 清理所有正在使用的资源。/// </summary>/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows 窗体设计器生成的代码/// <summary>/// 设计器支持所需的方法 - 不要修改/// 使用代码编辑器修改此方法的内容。/// </summary>private void InitializeComponent(){this.stNodeEditor1 = new ST.Library.UI.NodeEditor.STNodeEditor();this.btnConnectLine = new System.Windows.Forms.Button();this.SuspendLayout();// // stNodeEditor1// this.stNodeEditor1.AllowDrop = true;this.stNodeEditor1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(34)))), ((int)(((byte)(34)))), ((int)(((byte)(34)))));this.stNodeEditor1.Curvature = 0.3F;this.stNodeEditor1.Location = new System.Drawing.Point(12, 67);this.stNodeEditor1.LocationBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));this.stNodeEditor1.MarkBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));this.stNodeEditor1.MarkForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));this.stNodeEditor1.MinimumSize = new System.Drawing.Size(100, 100);this.stNodeEditor1.Name = "stNodeEditor1";this.stNodeEditor1.Size = new System.Drawing.Size(1160, 475);this.stNodeEditor1.TabIndex = 0;this.stNodeEditor1.Text = "stNodeEditor1";// // btnConnectLine// this.btnConnectLine.Font = new System.Drawing.Font("宋体", 16F);this.btnConnectLine.Location = new System.Drawing.Point(52, 12);this.btnConnectLine.Name = "btnConnectLine";this.btnConnectLine.Size = new System.Drawing.Size(169, 33);this.btnConnectLine.TabIndex = 1;this.btnConnectLine.Text = "连线-显示时间";this.btnConnectLine.UseVisualStyleBackColor = true;this.btnConnectLine.Click += new System.EventHandler(this.btnConnectLine_Click);// // FormSTNode// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(1200, 554);this.Controls.Add(this.btnConnectLine);this.Controls.Add(this.stNodeEditor1);this.Name = "FormSTNode";this.Text = "STNodeEditor开源框架,输入输出";this.Load += new System.EventHandler(this.FormSTNode_Load);this.ResumeLayout(false);}#endregionprivate ST.Library.UI.NodeEditor.STNodeEditor stNodeEditor1;private System.Windows.Forms.Button btnConnectLine;}
}

窗体FormSTNode.cs测试代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;using ST.Library.UI.NodeEditor;namespace STNodeDemo
{public partial class FormSTNode : Form{public FormSTNode(){InitializeComponent();//参考地址 https://blog.csdn.net/crystal_lz/article/details/117131080/*single-connection
单连接模式 在单连接模式下一个连接点同时 只能被一个 同数据类型点的连接
multi-connection
多连接模式 在多连接模式下一个连接点同时 可以被多个 同数据类型点连接数据交互:STNodeOption可以通过绑定DataTransfer事件获取到传入该选项的所有数据
STNodeOption可以通过TransferData(object obj)向该选项上所有连接的选项进行数据投递*/}private void FormSTNode_Load(object sender, EventArgs e){SnakeNode stNode = new SnakeNode("STNode的标题");stNode.Location = new Point(10, 10);stNodeEditor1.Nodes.Add(stNode);ViperNode destNode = new ViperNode("显示时间");destNode.Location = new Point(400, 10);stNodeEditor1.Nodes.Add(destNode);}/// <summary>/// 获取指定的输出节点选项/// </summary>/// <param name="node"></param>/// <param name="strText"></param>/// <returns></returns>private STNodeOption GetOutNodeOption(SnakeNode node, string strText) {STNodeOption outNodeOption = node.OutputOptionCollection.FirstOrDefault(option => option.Text == strText);return outNodeOption;}/// <summary>/// 获取指定的输入节点选项/// </summary>/// <param name="node"></param>/// <param name="strText"></param>/// <returns></returns>private STNodeOption GetInNodeOption(ViperNode node, string strText){STNodeOption inNodeOption = node.InputOptionCollection.FirstOrDefault(option => option.Text == strText);return inNodeOption;}private void btnConnectLine_Click(object sender, EventArgs e){STNodeOption outNodeOption = GetOutNodeOption((SnakeNode)stNodeEditor1.Nodes[0], "OutputTime");STNodeOption inNodeOption = GetInNodeOption((ViperNode)stNodeEditor1.Nodes[1], "ViperTime");ConnectionStatus connectionStatus = outNodeOption.ConnectOption(inNodeOption);MessageBox.Show($"输出节点 连接 输入节点 的状态结果【{connectionStatus}】", "提示");}}
}

测试运行如图:

相关文章:

开源节点框架STNodeEditor使用

节点&#xff0c;一般都为树形Tree结构&#xff0c;如TreeNode&#xff0c;XmlNode。 树形结构有其关键属性Parent【父节点】&#xff0c;Children【子节点】 LinkedListNode为链表线性结构&#xff0c;有其关键属性Next【下一个】&#xff0c;Previous【上一个】&#xff0c…...

算法每日一题: Nim游戏 | 找规律

哈哈&#xff0c;大家好&#xff0c;我是星恒&#xff0c;今天的每日一题真开心&#xff0c;连做了3天牢&#xff0c;终于ak了一道&#xff0c;太不容易了 这道题其实就是找规律&#xff0c;刚开始我还以为是动归&#xff0c;但是列举了不少例子之后&#xff0c;发现有自己直接…...

分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别

分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别 目录 分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现G…...

Dockerfile保留字

目录 一、Dockerfile保留字是什么&#xff1f; 二、Docker构建流程 1. 从基础镜像运行容器 2. 执行指令并修改容器 3. 提交新的镜像层 4. 基于新镜像运行新容器 5. 执行下一条指令 6. 循环执行指令 7. 所有指令执行完成 三、保留字 1. FROM 使用基础镜像作为起点 2.…...

Linux的7个运行级别

目录 1、有那7个运行级别&#xff1f; 2、那么如何查看运行级别呢?  3、那么我想临时切换运行级别? 4、那么我想修改配置文件中的运行级别呢? 1、有那7个运行级别&#xff1f; 0&#xff1a;停机状态。系统默认运行级别不能设置为0&#xff0c;否则系统不能正常启动&a…...

Linux期末总复习( 详解 )

文章目录 一、选择题二、填空题三、简答题四、操作题 一、选择题 1.在创建Linux分区时&#xff0c;一定要创建&#xff08; D &#xff09;两个分区 A. FAT/NTFS  B. FAT/SWAP  C. NTFS/SWAP  D.SWAP/根分区 2.在Red Hat Linux 9 中&#xff0c;系统默认的&#xf…...

【Linux系统化学习】进程等待

目录 进程等待 进程等待的必要性 进程等待的方法 wait方法 等待一个进程(阻塞等待&#xff09; waitpid方法 任意等待多个进程&#xff08;阻塞等待&#xff09; 父进程获取子进程的退出信息 非阻塞轮询等待 进程等待 进程等待的必要性 之前讲过&#xff0c;子进程退…...

前端学习笔记 | HTML5+CSS3静态网页制作的技巧(持续更新)

注&#xff1a;本文的css样式均使用less写法 1、字体居中 &#xff08;1&#xff09;先text-align:center;行内元素水平居中 &#xff08;2&#xff09;再line-heigh:(盒子高度);行内元素垂直居中 text-align: center;line-height: ( 30 / vw ); 2、盒子居中 情景1&#…...

docker安装-centos

Docker CE 支持 64 位版本 CentOS 7&#xff0c;并且要求内核版本不低于 3.10 卸载旧版本Docker sudo yum remove docker \ docker-common \ docker-selinux \ docker-engine使用yum安装 yum 更新到最新版本: sudo yum update执行以下命令安装依赖包&#xff1a; sudo yum…...

Redis入门指南

文章目录 Redis概述Redis基本数据类型Redis与MySQL的区别以及使用场景如何保持双写一致性&#xff08;缓存一致性&#xff09;1. 延迟双删2. 分布式锁&#xff08;强一致性时使用&#xff09;3. 中间件 Redis持久化机制RDB&#xff08;redis database&#xff09;AOF&#xff0…...

K8s之configMap

1. 概述​ 1.1 什么是configMap​ 1.1 什么是configMap configMap是Kubernetes中的一种资源对象&#xff0c;用于存储配置数据。它可以包含键值对&#xff0c;也可以包含来自文件的配置数据。configMap的作用是将配置数据与应用程序的容器分离&#xff0c;使得配置可以在不重…...

提高 NFS Azure 文件共享性能

本文内容 适用于增加预读大小以提高读取吞吐量Nconnect另请参阅 本文介绍如何提高 NFS Azure 文件共享的性能。 适用于 展开表 文件共享类型SMBNFS标准文件共享 (GPv2)、LRS/ZRS 标准文件共享 (GPv2)、GRS/GZRS 高级文件共享 (FileStorage)、LRS/ZRS 增加预读大…...

【Django-ninja】使用schema

在Django Ninja中&#xff0c;"schema"主要是指帮助描述和规范你的API的工具&#xff0c;以便系统能够自动生成文档并提供验证。通俗地说&#xff0c;它有两个主要作用&#xff1a; API文档生成器&#xff1a; Schema 让 Django Ninja 能够自动生成互动式的API文档。…...

【TCP/IP】用户访问一个购物网站时TCP/IP五层参考模型中每一层的功能

当用户访问一个购物网站时&#xff0c;网络上的每一层都会涉及不同的协议&#xff0c;具体网络模型如下图所示。 以下是每个网络层及其相关的协议示例&#xff1a; 物理层&#xff1a;负责将比特流传输到物理媒介上&#xff0c;例如电缆或无线信号。所以在物理层&#xff0c;可…...

Unity 开发注意事项

1. 空Unity消息 Unity消息被运行时事件调用&#xff0c;即使消息体为空也会被调用。因此&#xff0c;删除空消息避免不必要的处理。 例如&#xff1a; using UnityEngine;class Camera : MonoBehaviour {private void FixedUpdate(){}private void Foo(){} } 应该删除未使用…...

[Unity Sentis] Unity Sentis 详细步骤工作流程

文章目录 1. 导入模型文件支持的模型创建运行时模型导入错误 2. 为模型创建输入将数组转换为张量创建多个输入进行操作 3. 创建一个引擎来运行模型创建一个Worker后端类型 4. 运行模型5. 获取模型的输出获取张量输出多个输出打印输出 1. 导入模型文件 要导入 ONNX 模型文件&am…...

力扣144 二叉树的前序遍历 Java版本

文章目录 题目描述递归方法代码 非递归方法代码 题目描述 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xf…...

《Vue3 基础知识》 使用 GoGoCod 升级到Vue3+ElementPlus 适配处理

此篇为 《Vue2ElementUI 自动转 Vue3ElementPlus&#xff08;GoGoCode&#xff09;》 的扩展&#xff01; Vue3 适配 Vue3 不兼容适配 Vue 3 迁移指南 在此&#xff0c;本章只讲述项目或组件库中遇到的问题&#xff1b; Vue3 移除 o n &#xff0c; on&#xff0c; on&#…...

c#string方法对比

字符串的截取匹配操作在开发中非常常见&#xff0c;比如下面这个示例&#xff1a;我要匹配查找出来字符串数组中以“abc”开头的字符串并打印&#xff0c;我下面分别用了两种方式实现&#xff0c;代码如下&#xff1a; using System; namespace ConsoleApp23{ class Progra…...

Electron实战(一):环境搭建/Hello World/打包exe

文章目录 Electron安装Node.jsNodeJs推荐配置开始Electron项目创建index.js文件创建src目录运行打包生成exe生成安装包踩坑 下一篇Electron实战(二)&#xff1a;将Node.js和UI能力&#xff08;app/BrowserWindow/dialog)等注入html Electron Electron是一个使用JavaScript, HT…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...