开源节点框架STNodeEditor使用

news/2024/7/10 21:33:43 标签: 开源, STNode, 流程编辑器

节点,一般都为树形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.niftyadmin.cn/n/5365101.html

相关文章

探索设计模式的魅力:从单一继承到组合模式-软件设计的演变与未来

设计模式专栏&#xff1a;http://t.csdnimg.cn/nolNS 在面对层次结构和树状数据结构的软件设计任务时&#xff0c;我们如何优雅地处理单个对象与组合对象的一致性问题&#xff1f;组合模式&#xff08;Composite Pattern&#xff09;为此提供了一种简洁高效的解决方案。通过本…

istio 限流

#详细参数看官网&#xff0c;我参数就不解释https://istio.io/latest/docs/reference/config/networking/destination-rule/cat << EOF > dr.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata:name: my-testnamespace: demon spec:hos…

(5)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—12种聚类算法说明与归纳

目录 一、12种聚类(无监督学习)算法说明和区分比较 聚类算法的类型(一) ​编辑导入函数库 加载数据集 ​编辑 (1)K-Means --Centroid models (2)Mini-Batch K-Means -- Centroid models (3)AffinityPropagation (Hierarchical) -- Connectivity models (4)Mean Shift…

探索自然语言处理在改善搜索引擎、语音助手和机器翻译中的应用

文章目录 每日一句正能量前言文本分析语音识别机器翻译语义分析自然语言生成情感分析后记 每日一句正能量 努力学习&#xff0c;勤奋工作&#xff0c;让青春更加光彩。 前言 自然语言处理&#xff08;NLP&#xff09;是人工智能领域中与人类语言相关的重要研究方向&#xff0c…

蓝桥杯Web应用开发-display属性

display 属性 专栏持续更新中 display 属性可以用来设置元素在页面上的排列方式&#xff0c;也可用来隐藏元素。 display 属性值的说明如下表所示。 属性值说明block元素以块级方式展示。inline元素以内联方式展示。inline-block元素以内联块的方式展示。none隐藏元素。 b…

rancher迁移账号密码

1. 登陆rancher容器获取user【docker部署和helm部署都一样&#xff0c;进到容器内都是同一路径】 $ kubectl get user NAME AGE u-222ms 82m u-4j5jf 82m u-b4qkhsnliz 139d u-fvj64 83m u-jn58d 84m u-llw8l 83m u-mo773ytt…

【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“

使用idea运行项目&#xff0c;显示错误信息如下&#xff1a; 原因是&#xff1a;idea配置的maven加载不到autoconfigure。 解决方案一&#xff1a; 第6步绕过证书语句如下&#xff1a; -Dmaven.wagon.http.ssl.insecuretrue -Dmaven.wagon.http.ssl.allowalltrue 打开终端&am…

【代码随想录-哈希表】两个数组的交集

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…