开源节点框架STNodeEditor使用

news2024/11/27 14:53:03

节点,一般都为树形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.coloradmin.cn/o/1433008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零信任实施:计划,执行,一步一步

去年&#xff0c;82% 的网络安全专业人员一直致力于实施零信任&#xff0c;到今年年底&#xff0c;应有 16% 的网络安全专业人员开始实施零信任。 零信任实施的挑战 您可能以前听说过&#xff1a;零信任不是单一产品&#xff0c;而是遵循“从不信任&#xff0c;始终验证”原则…

【Linux】进程间通信 --管道通信

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法…感兴趣就关注我吧&#xff01;你定不会失望。 本篇导航 0. 进程间通信原理1. 匿名管道1.1 通信原理1.2 接口介绍 2. 命名管道2.1 接口介绍 3. 共享内存3.1 通信原理3.2 接口介绍 0. 进…

Java GC-常见垃圾回收器

目录 前言一、垃圾回收器分类二、垃圾回收器介绍1、Serial 收集器2、ParNew 收集器3、Parallel Scavenge 收集器4、Serial Old 收集器5、Parallel Old 收集器6、CMS 收集器&#xff08;多线程标记清除算法&#xff09;7、G1 收集器 三、项目中垃圾收集器选型 前言 Java的垃圾回…

零基础学编程系列,从入门到精通,中文编程开发语言工具下载,编程构件容器件之控制面板构件用法

零基础学编程系列&#xff0c;从入门到精通&#xff0c;中文编程开发语言工具下载&#xff0c;编程构件容器件之控制面板构件用法 一、前言 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载…

银河麒麟 aarch64 Mysql环境安装

一、操作系统版本信息 组件版本操作系统Kylin V10 (SP3) /(Lance)-aarch64-Build23/20230324Kernel4.19.90-52.22.v2207.ky10.aarch64MySQLmysql-8.3.0JDK1.8.0_312 二、MySQL下载 官网下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 三、MySQL 安装 3.1 删…

幻兽帕鲁一键迁移到服务器,本地迁移存档后为什么又需要重新创建角色?

最近很多人在玩幻兽帕鲁的时候&#xff0c;想要把本地游戏存档迁移到服务器上继续玩&#xff0c;有些朋友却发现通过阿里云或者腾讯云上的一键迁移导入之后&#xff0c;进入游戏后发现又要重头开始玩。 这是为什么呢&#xff1f;其中可能的原因&#xff0c;我想就是因为它们的一…

spring boot3x登录开发-上(整合jwt)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途。 目录 前置条件 jwt简介 导依赖 编写jwt工具类 1.配置项直接嵌入代码&#xff0c;通过类名.静态方法使用 2.配置项写到…

ROS2学习(一):Ubuntu 20.04 安装 ROS2(Galactic Geochelone)

文章目录 一、ROS2(Galactic Geochelone)介绍二、ROS2(Galactic Geochelone)安装1. 设置语言环境2. 配置ubuntu universe仓库3. 配置ros2 apt仓库4. 安装ros25. 安装情况测试 一、ROS2(Galactic Geochelone)介绍 官方文档 二、ROS2(Galactic Geochelone)安装 1. 设置语言环…

[嵌入式AI从0开始到入土]5_炼丹炉的搭建(基于wsl2_Ubuntu22.04)

[嵌入式AI从0开始到入土]嵌入式AI系列教程 注&#xff1a;等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间&#xff0c;后期会考虑出视频教程&#xff0c;务必催更&#xff0c;以防我变身鸽王。 第一章 昇腾Altas 200 DK上手 第二章 下载昇腾案例并运行 第三章…

云上未来:探索云计算的技术变革与应用趋势

一、云计算的起源和演进 1.1 早期计算模型 在探讨云计算的起源和演进之前&#xff0c;理解早期的计算模型对于构建全面的视角至关重要。早期计算模型的发展奠定了云计算的基础&#xff0c;为其演进提供了技术和理念的支撑。 1.1.1 集中式计算模型 在计算技术的早期阶段&…

使用Python和HTTP代理进行API请求

Python&#xff0c;这个简单易学又功能强大的编程语言&#xff0c;在网络爬虫、数据分析、自动化任务等领域都有着广泛的应用。而当我们需要从外部网站获取数据时&#xff0c;API&#xff08;应用程序接口&#xff09;就成了我们的得力助手。但有时候&#xff0c;某些网站会对A…

问题:下面几个句子,是对排比修辞方法的论述,正确的是() #笔记#知识分享

问题&#xff1a;下面几个句子&#xff0c;是对排比修辞方法的论述&#xff0c;正确的是&#xff08;&#xff09; A&#xff0e;排比是结构上相同或相似的短语或句子构成&#xff0c;成串排列&#xff0c;以增强语势 B&#xff0e;排比是侧重于同一词语或同一句子一再出现&a…

WordPress Plugin HTML5 Video Player SQL注入漏洞复现(CVE-2024-1061)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 0x02 漏洞概述 WordPress Plugin HTML5 Video Player 插件 get_v…

游戏视频录制软件推荐,打造专业电竞视频(3款)

随着游戏产业的快速发展&#xff0c;越来越多的玩家开始关注游戏视频录制软件。一款好的录制软件不仅可以帮助玩家记录游戏中的精彩瞬间&#xff0c;还可以让其与他人分享自己的游戏体验。接下来&#xff0c;我们将介绍三款热门的游戏视频录制软件&#xff0c;并对其进行详细的…

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…

2024三掌柜赠书活动第八期:Web3与DAO:下一代互联网演进逻辑

目录 前言关于Web3和DAO关于《Web3与DAO&#xff1a;下一代互联网演进逻辑》编辑推荐内容简介作者简介精彩书评图书目录书中前言/序言《Web3与DAO&#xff1a;下一代互联网演进逻辑》全书速览结束语 前言 随着区块链技术的崛起&#xff0c;Web3和DAO成为了当前互联网领域炙手…

vivado 综合、时序分析

以下综合 运行完成后&#xff0c;将打开Synthesis Completed对话框&#xff0c;如下所示图形 选择其中一个选项&#xff1a; •运行实施&#xff1a;启动当前实施项目的实施设置。 •打开综合设计&#xff1a;打开综合网表、活动约束集和将目标设备集成到综合设计环境中&…

利用k8s Infra 容器,解决pod网络故障注入的问题

目录 一、infra容器作用 二、pod网络故障注入问题 三、充分利用pod infra容器 一、infra容器的作用 我们知道&#xff0c;在kubernetes中&#xff0c;pod中容器的资源隔离主要通过namespace和cgroup来实现。那如果我们需要为pod中的容器共享某种资源应该怎么做。kubernetes …

组合数学基础

隔板法 X 1 X 2 . . . X n m , X i > 0 X_1X_2...X_nm,\quad X_i>0 X1​X2​...Xn​m,Xi​>0 求方程解的个数 求方程解的个数 求方程解的个数 m 个球插入 n − 1 个板将 m 个球分成 n 份 m个球插入n-1个板将m个球分成n份 m个球插入n−1个板将m个球分成n份 方程…

如何排查常规软件问题 - 面向 Linux 初级用户的教程

笔者从 14 年做开源软件以来&#xff0c;接触了众多 Linux 新手用户&#xff0c;这里我为这类用户总结了一些常见的问题排查方法&#xff0c;希望能帮助到大家。如果你已经工作多年&#xff0c;对于下面提到的思路和方法应该非常熟悉&#xff0c;如果对某一条感到陌生&#xff…