开源节点框架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);

        }

        #endregion

        private 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}】", "提示");
        }
    }
}

测试运行如图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/371810.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--强化学习、模仿学习、机器人

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

源码梳理(2)SpringMVC的执行流程及涉及到的相关组件

文章目录 1&#xff0c;Spring MVC核心组件DispatcherServlet1.1 DispatcherServlet的继承关系1.2 DispatcherServlet的doDispatch方法 2&#xff0c;核心组件HandlerMapping&#xff08;处理器映射器&#xff09;3&#xff0c;核心组件HandlerAdapter&#xff08;处理器适配器…

前端文艺复兴:Vue3真的需要Pinia吗?

前言 说起Pinia&#xff0c;熟悉 vue3 开发的程序员肯定不会陌生&#xff0c;甚至被vue官方推荐取代vuex&#xff0c;成为vue全家桶之一。 疑惑 还记得之前用 vuex 时&#xff0c;更改 state 还分同步和异步&#xff08;这里有尤雨溪的回答www.zhihu.com/question/48… &…

Hadoop-生产调优

第1章 HDFS-核心参数 1.1 NameNode内存生产配置 1&#xff09;NameNode 内存计算 每个文件块大概占用 150 byte&#xff0c;一台服务器 128G 内存为例&#xff0c;能存储多少文件块呢&#xff1f; 128 * 1024 * 1024 * 1024 / 150byte ≈ 9.1 亿G MB KB Byte 2&#xff09…

undefined symbol: avio_protocol_get_class, version LIBAVFORMAT_58

rv1126上进行编译和在虚拟机里面进行交叉编译ffmpeg都不行 解决办法查看 查看安装的ffmpeg链接的文件 ldd ./ffmpeg rootEASY-EAI-NANO:/home/nano/ffmpeg-4.3.6# ldd ffmpeg linux-vdso.so.1 (0xaeebd000)libavdevice.so.58 > /lib/arm-linux-gnueabihf/libavde…

continue语句

一、continue语句 1、continue语句介绍 2、continue语句流程图 3、快速入门案例 4、continue语句的标签

基于Go-Kit的Golang整洁架构实践

如何用Golang实现简洁架构&#xff1f;本文介绍了基于Go-Kit实现简洁架构的尝试&#xff0c;通过示例介绍了简洁架构的具体实现。原文: Why is Go-Kit Perfect For Clean Architecture in Golang? 简介 Go是整洁架构(Clean Architecture)的完美选择。整洁架构本身只是一种方法…

基于python+控制台的车辆信息管理系统

基于python控制台的车辆信息管理系统 一、系统介绍二、效果展示三、其他系统实现四、获取源码 一、系统介绍 打印功能菜单、添加车辆信息、删除车辆信息、修改车辆信息、显示车辆信息、退出系统&#xff0c;并且需要接收用户的输入&#xff0c;在根据输入内容调用相应函数实现…

深度学习介绍

对于具备完善业务逻辑的任务&#xff0c;大多数情况下&#xff0c;正常的人都可以给出一个符合业务逻辑的应用程序。但是对于一些包含超过人类所能考虑到的逻辑的任务&#xff0c;例如面对如下任务&#xff1a; 编写一个应用程序&#xff0c;接受地理信息、卫星图像和一些历史…

指针的深入理解(四)

这节主要讨论sizeof和strlen的区别&#xff0c;以及一些理解题。 sizeof 求的是对象的大小&#xff0c;深入理解一点就是&#xff1a;这个对象&#xff0c;他一定有一块对应的内存空间。求的就是这一块内存空间。 strlen 只能用来求字符串&#xff0c; 求取的是字符串的长度。…

Unity中blendtree和state间的过渡

混合树状态之间的过渡 如果属于此过渡的当前状态或下一状态是混合树状态&#xff0c;则混合树参数将出现在 Inspector 中。通过调整这些值可预览在混合树值设置为不同配置时的过渡表现情况。 如果混合树包含不同长度的剪辑&#xff0c;您应该测试在显示短剪辑和长剪辑时的过渡表…

Mocaverse NFT 概览与数据分析

作者&#xff1a;stellafootprint.network 编译&#xff1a;mingfootprint.network 数据源&#xff1a;Mocaverse NFT Collection Dashboard Mocaverse 是 Animoca Brands 推出的专属 NFT&#xff08;非同质化代币&#xff09;系列&#xff0c;包含 8,888 个独特的 "M…

深入理解TCP网络协议(3)

目录 1.前言 2.流量控制 2.阻塞控制 3.延时应答 4.捎带应答 5.面向字节流 6.缓冲区 7.粘包问题 8.TCP异常情况 9.小结 1.前言 在前面的博客中,我们重点介绍了TCP协议的一些属性,有连接属性的三次握手和四次挥手,还有保证数据安全的重传机制和确认应答,还有为了提高效率…

2024美赛E题成品论文22页详细讲解+完整代码数据汇总

E题社区抗灾能力综合评估与决策模型研究 &#xff08;完整版在文末&#xff09; 摘要&#xff1a;社区抗灾能力的提升对于灾害风险管理至关重要。本研究基于机器学 习方法&#xff0c;构建了社区抗灾能力预测模型&#xff0c;以评估社区在灾害事件中的表现。首先&#xff0c; 我…

在maven环境中使用GraalVM来构建本地原生应用程序(一)构建本地可执行文件

文章目录 前言一、GraalVM安装二、初步使用三、踩坑记录1、JSON转换问题2、反射、资源、jni的调用问题3、HTTPS调用问题4、Linux下CPU架构问题5、Linux下GLIBC版本的问题6、部分Windows系统无法缺少相关的库文件 总结 前言 随着Java17的更新&#xff0c;jdk又推出了一个GraalV…

【lesson10】高并发内存池细节优化

文章目录 大于256KB的大块内存申请问题大于256KB的大块释放申请问题使用定长内存池脱离使用new释放对象时优化为不传对象大小完整版代码Common.hObjectPool.hThreadCache.hThreadCache.cppConcurrentAlloc.hCentralCache.hCentralCache.cppPageCache.hPageCache.cpp 大于256KB的…

SpringBoot中数据库的连接及Mybatis的配置和使用

目录 1 在pom.xml中引入相关依赖 2 对数据库进行配置 2.1 配置application.yml 2.2 idea连接数据库 (3.2.1有用到) 3 Mybatis的使用 3.1 测试文件的引入 3.2 使用 3.2.1 使用注解(有小技巧(✪ω✪)) 3.2.2 使用动态sql 1 在pom.xml中引入相关依赖 <dependencies&g…

【DDD】学习笔记-EAS 的整体架构实践

为了得到系统的整体架构&#xff0c;我们还欠缺什么呢&#xff1f;所谓“架构”&#xff0c;是“以组件、组件之间的关系、组件与环境之间的关系为内容的某一系统的基本组织结构&#xff0c;以及指导上述内容设计与演化的原则”。之所以要确定系统的组件、组件关系以及设计与演…

线上编程答疑解惑回顾,初学编程中文编程在线屏幕共享演示

线上编程答疑解惑回顾&#xff0c;初学编程中文编程在线屏幕共享演示 一、学编程过程中有不懂的怎么办&#xff1f; 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载——常用工具下载——编…

基于深度学习的SSVEP分类算法简介

基于深度学习的SSVEP分类算法简介 1、目标与范畴2、深度学习的算法介绍3、参考文献 1、目标与范畴 稳态视觉诱发电位&#xff08;SSVEP&#xff09;是指当受试者持续注视固定频率的闪光或翻转刺激时&#xff0c;在大脑枕-额叶区域诱发的与刺激频率相关的电生理信号。与P300、运…
最新文章