要做数采?没资料?没教程?来吧孩子让我拯救你

CNC数采最全教程

三菱篇章

一、介绍

1.背景

​ 注:这篇是我将发那科CNC采集与三菱CNC采集一起集成,并且做了代码优化,并且支持了Mysql本地配置传输数据。

​ 这是我在接手MES系统的生产采集功能时,花费巨大心血,才掌握的应该设备采集数据的教程。如果你也因为网上教程太杂,而且不附带资源,那么你就找对了文档,制作不易,请点赞收藏。

​ 顺便给大家看看一下采集的效果,看看是不是大家需要的功能,这里我还要说一下,我只采集了我需要的,什么坐标,刀具信息什么的需要大家自己看我提供的资料文档,然后再去采集出来。

在这里插入图片描述

2.需要掌握知识

​ C#,winform这个语言有基本的语法掌握,Mysql语言要学会增删改操作,VS工具的使用

3.需要资料
①三菱SDK包:A2

​ 下载地址:三菱CNC数据采集与驱动A2协议手册:三菱CNC数据采集与驱动A2协议手册欢迎使用《三菱CNC - 三菱数控系统 - 数据采集 - 驱动 - A2驱动,协议手册》 - GitCode

​ 下载后一路下一步安装,遇到需要解锁的激活码时,就在A2包里面的,SN.txt文本里面

②三菱com接口文档

​ FCSB1224W000PDF文档

③C#代码:

​ SimCNC-master

④VStudio

​ 浏览器直接搜索下载,不过vs下载时要注意下载包含winform的负载包

在这里插入图片描述

⑤资料存放网盘

​ 这些我全都放在我的百度网盘里面,这个是网盘的地址大家可以自己去下载,但是vs这个需要自己去网上安装。

​ 通过百度网盘分享的文件:三菱设备采集教程
​ 链接:https://pan.baidu.com/s/1RRG-sKQcYtK_1q9sNR1Qyw?pwd=love
​ 提取码:love

​ 因为百度有点恶心人,上传资源分享都不能传文件夹,我这边就把最新更新的项目以及资料放gitcode,优快云推出的代码仓,非常Nice

​ 地址:项目首页 - 数据采集教程资料:数据采集资料 - GitCode

二、程序运行

1.调试设备
①条件

​ 你需要调试三菱的设备IP让其可以被ping通

​ 还要确保你和三菱机床要是同一个网段下

②命令

​ –ipconfig

​ 电脑在命令窗口使用 ipconfig查看IPV4的地址,来确定自己电脑在哪一个网段。

​ 我用虚拟机的,网卡设备太多,不过大家电脑就不会这么多,一眼就能看到自己所在网段

在这里插入图片描述

​ –arp -a

​ 电脑在命令窗口使用 arp -a查看这个网段下面存活的设备
在这里插入图片描述

​ –设置设备IP

​ 确定好设备可以使用的IP后,就去设置CNC机床的IP,这是一个调试设备IP的文档:

机床数据采集之Mitsubishi三菱M70/M80数控IP地址参数设定_三菱m70以太网设定教程-优快云博客

2.运行软件
打开软件

​ 双击打开会让你选择打开软件,我们选择vs2022这个紫色图标就行了

在这里插入图片描述

运行程序

​ 运行起来后,就直接按连接按钮,看看是否能够采集到数据就行了

在这里插入图片描述

在这里插入图片描述

三、数据采集

1.代码了解

注意:ctrl+鼠标单击进入,我截图有一个文字写错了

在这里插入图片描述

在这里插入图片描述

​ 进入后我们就能看到一堆COM接口的方法,我们并不清楚文档里面方法是干嘛,这时候我们就需要打开PFf的参考手册了

2.参考手册

​ 打开FCSB1224W000PDF 参考手册PDF文件

在这里插入图片描述

3.采集案例
①找需要的数据

​ 我们从参考手册里面找到我们要采集的数据,例如AliveTime

在这里插入图片描述

②找接口方法

​ --我们在代码里面找到我们手册里面的的接口方法

​ --我们能看到返回的是int的数据,然后要传入一个out int plTime的参数

​ --int不解释了,这个out就是值传递意思,从外部传入的值,在里面值发生改变会传递到外部

在这里插入图片描述

③实现方法

​ --因为我们的界面中调用的都是MitCom类中的方法,所以我们要在这个类写个方法

​ --完成后可以在我们的代码中通过mitCom对象调用了

 /**
  * 获取电源开启到关闭的时间
  */
 public void GetRunAliveTime(out int plTime)
 {
     //初始化运行时间为0,会因为out而修改掉
     plTime = 0;
     try
     {
         if (EZNcCom != null)
         {
             lResult = EZNcCom.Time_GetAliveTime(out plTime);
             ErrorCheck("GetRunAliveTime");
         }
     }
     catch
     {
         ErrorCheck("通讯已关闭");
     }
 }

四、代码思路

1.总结代码

​ --我的代码全部总结出来,其实就四个内容

在这里插入图片描述

2.初始化
①思路

​ --初始化连接池

​ --初始化零件加工循环时间判断类

​ --装载连接IP的容器创建

​ --在程序执行时会执行无参构造方法,在立马初始化表格头,还有连接池的连接对象,和循环时间判断类装载

​ --优化思路:把三菱的连接池,包括其他的需要初始化的数据,全部放到一个类中,写成对象数组

②代码
#region 初始化相关内容
//--------------------------------------------
//懒得写个对象数组了,大家想优化可以自己写
//int connCount = 0;//连接池初始化的次数,用来防止频繁创建连接
List<EZSockets.MitCom> mitComs = new List<EZSockets.MitCom>();//模拟连接池

//零件加工循环时间判断类
List<PartCycleTimeChecker> pctCheckers = new List<PartCycleTimeChecker>();//
//---------------------------------------------

//获取连接IP的数据
List<String> nodes = new List<string>();

public MultipleMitForm()
{
    InitializeComponent();

    init();

    //初始化连接个数
    //默认初始化连接个数 10个
    connectionInit(10);
}

public void init()
{
    //设置列名
    dataGridView1.Columns.Clear();
    dataGridView1.Columns.Add("version", "版本信息:");
    dataGridView1.Columns.Add("aliveTime", "设备状态:");
    dataGridView1.Columns.Add("processCount", "零件加工总数:");
    dataGridView1.Columns.Add("waringMessage", "告警信息:");
    dataGridView1.Columns.Add("runTime", "运行时间:");
    dataGridView1.Columns.Add("runStatus", "运行状态:");
    dataGridView1.Columns.Add("CNCTime", "机床加工时间:");
    dataGridView1.Columns.Add("processTime", "目前零件加工时间:");
    // 设置列宽
    dataGridView1.Columns["processCount"].Width = 130; // 设置宽度为 100 像素
    dataGridView1.Columns["waringMessage"].Width = 150; // 设置宽度为 100 像素
    dataGridView1.Columns["CNCTime"].Width = 130; // 设置宽度为 100 像素
    dataGridView1.Columns["processTime"].Width = 150; // 设置宽度为 100 像素

}
#endregion
3.连接方法
①思路

​ --这个初始化连接的详细方法

​ --进行输入连接地址的获取方法

​ --点击连接按钮进行连接事件

​ --连接数修改的方法

​ --防止窗口关闭忘记断开连接的的方法

②代码
 #region 连接相关方法群
 //初始化连接池
 public void connectionInit(int connCount)
 {
     //清空连接池
     mitComs.Clear();

     // 设置连接数的文本信息
     this.formMitConnSum.Text = "" + connCount;
     //设置更新连接数判断参数 发生变化时用来比对
     updateConneSum = connCount;

     //默认初始化连接个数 10个
     for (int i = 1; i <= connCount; i++)
     {
         EZSockets.MitCom mitCom = new MitCom();
         mitComs.Add(mitCom);

         PartCycleTimeChecker pctCheck = new PartCycleTimeChecker();
         pctCheckers.Add(pctCheck);
     }
     Console.WriteLine("connectionInit:" + mitComs.Count);
 }

 // 方法:获取每行文本并填充集合
 private List<string> GetLinesFromTextBox(TextBox textBox)
 {
     // 创建一个集合来存放每一行文本
     List<string> lines = new List<string>();

     // 将多行文本框的内容按行分割
     foreach (string line in textBox.Lines)
     {
         // 添加到集合
         if (!string.IsNullOrWhiteSpace(line)) // 检查非空行
         {
             lines.Add(line);
         }
     }
     return lines; // 返回包含每行文本的集合
 }


 private void Connect_Click(object sender, EventArgs e)
 {
     //读取你输入IP作为一个数组
     nodes = GetLinesFromTextBox(nodeNames);

     //连接状态
     string connStatus = Connect.Text;

     string version = "";
     int pvValue;

     //非空判断,IP输入数不合理判断
     if (nodes.Count < 1)
     {
         MessageBox.Show("请输入IP", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
         return;
     }

     //连接数判断 为false 就进入判断结束方法
     if (!connectionCountChanged())
     {
         return;
     }

     try
     {
         if (connStatus == "连接")
         {
             //连接状态禁止修改
             nodeNames.ReadOnly = true;
             formMitConnSum.ReadOnly = true;

             for (int i = 0; i < nodes.Count; i++)
             {
                 //初始化连接池的连接
                 mitComs[i].GetSimConnect("M700M", "" + i + 1, TimeOut.Text, nodes[i]);//连接三菱设备
                 Connect.Text = "断开";
             }

             //读取一下数据
             readData();
         }

         if (connStatus == "断开")
         {
             //清除表格旧数据
             readCount = 0;
             dataGridView1.Rows.Clear();

             //连接状态禁止修改
             nodeNames.ReadOnly = false;
             formMitConnSum.ReadOnly = false;
             for (int i = 0; i < nodes.Count; i++)
             {
                 version = "";
                 //断开指定连接
                 //初始化连接池的连接
                 mitComs[i].GetSimConnect("M700M", "" + i + 1, TimeOut.Text, nodes[i]);//连接三菱设备

                 //初始化标记是否可以计数
                 pctCheckers[i].RunCount = 0;

                 Connect.Text = "连接";
             }
         }
     }
     catch (Exception ex)
     {
         MessageBox.Show($" 连接/断开 过程中出现错误: {ex.Message}");
     }

 }

 //连接数修改方法
 int updateConneSum = 0;

 bool connectionCountChanged()
 {
     Console.WriteLine("连接池个数:" + mitComs.Count);
     Console.WriteLine("连接个数:" + nodes.Count);
     

     bool flag = true;
     // 尝试解析输入内容,符合整数才能继续判断
     if (int.TryParse(formMitConnSum.Text, out int connectionCount))
     {
         //检查输入IP个数是否超出设定连接数据 
         if (nodes.Count > Convert.ToInt32(mitComs.Count) )
         {
             MessageBox.Show("检查输入IP个数是否超出设定连接数据", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
             flag = false;
         }
         

         //当连接数发生变化时,就修改连接数
         if(Convert.ToInt32(formMitConnSum.Text) > updateConneSum)
         {
             Console.WriteLine("连接数发生修改:"+ connectionCount);
             updateConneSum = Convert.ToInt32(formMitConnSum.Text);
             // 修改连接池个数
             connectionInit(Convert.ToInt32(formMitConnSum.Text));
         }
     }
     else
     {
         // 输入无效的情况,可提示用户
         MessageBox.Show("请输入有效的连接数", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
         // 此行可以选用取消输入或清空内容
         // connectionSum.Clear(); // 可选
         flag = false;
     }

     return flag;
 }

 //窗体关闭前先关闭连接
 private void MultipleMitForm_FormClosing(object sender, FormClosingEventArgs e)
 {
     Console.WriteLine("窗口关闭前!!!!!!!!!!!!!!!!");
     if (Connect.Text == "断开")
     {
         Connect_Click(sender, e);
     }
 }

 private void MultipleMitForm_FormClosed(object sender, FormClosedEventArgs e)
 {
     Console.WriteLine("窗口关闭后!!!!!!!!!!!!!!!!");
     if (Connect.Text == "断开")
     {
         Connect_Click(sender, e);
     }
 }

 #endregion
4.获取信息方法
①思路

​ --首先找到接口文档手册,查阅到需要的方法

​ --然后去找到通讯类中的接口,进行调用,忘记的可以到三、数据采集去看看

​ --我们可以看看三菱官方写的MitCom类中有没有大家需要的方法

​ --假设没有,我们就需要在MitCom中创建好,然后在页面中进行调用

②案例

​ --假设我们要写一个获取电源时间的,且MitCom中没有

​ --1.我们按照标题三、数据采集的方法找到这个方法

​ --2.在MitCom完成方法的实现

​ --3.在我们的界面中进行调用,以及修改表格展示初始化,和表格数据的读取

​ --4.代码中要修改的地方

添加列名到表格

dataGridView1.Columns.Add("aliveTime", "电源时间:");

添加数据表表格行

dataGridView1.Rows.Add(GetAliveTime(mitComs[i]));

循环读取内容时,进行修改表格数据

row.Cells[0].Value = GetAliveTime(mitComs[i]);

1..在我们的界面中进行调用
		/// <summary>
        /// 获取电源运行时间
        /// </summary>
        string GetAliveTime(EZSockets.MitCom mitCom)
        {
            int plTime;

            mitCom.GetRunAliveTime(out plTime);

            if (plTime > 0)
            {
                return "在线";
            }
            else
            {
                return "离线";
            }
        }
		
2.以及修改表格展示初始化
        public void init()
        {
            //设置列名
            dataGridView1.Columns.Clear();
            dataGridView1.Columns.Add("aliveTime", "电源时间:");
        }

3.表格数据的读取
 //读取需要的数据
 int readCount = 0; //表格读取次数
 public void readData()
 {
     //获取连接IP的数据
     List<String> nodes = GetLinesFromTextBox(nodeNames);

     this.BeginInvoke((MethodInvoker)delegate ()
     {
         Console.WriteLine("表格读取次数:" + readCount);
         Console.WriteLine("表格行数:" + dataGridView1.RowCount);
         //如果
         if (readCount == 0 && dataGridView1.RowCount <= 1)
         {
             //清除表格行数据
             dataGridView1.Rows.Clear();
             for (int i = 0; i < nodes.Count; i++)
             {
                 //,GetCount(mitComs[i])
                 dataGridView1.Rows.Add(GetAliveTime(mitComs[i]));
                 readCount++;
             }
         }
         else
         {
             //清除表格行数据
             for (int i = 0; i < nodes.Count; i++)
             {
                 // 更新已有行
                 DataGridViewRow row = dataGridView1.Rows[i];
                 row.Cells[0].Value = GetAliveTime(mitComs[i]);
             }
         }
     });
 }
③代码
#region 获取信息的方法群
/// <summary>
/// 获取零件运行时间
/// </summary>
string GetEstimateTime(EZSockets.MitCom mitCom, PartCycleTimeChecker pctChecker)
{ 
    //获取当前运行状态
    string stauts = GetRunStatus(mitCom);

    // 获取当前时间
    DateTime now = DateTime.Now;
    // 将时、分、秒转换为总秒数
    int currentTime = (now.Hour * 3600) + (now.Minute * 60) + now.Second;

    //新的一轮开始判断
    if(stauts == "未运行")
    {
        //判断是否为新的一轮
        if (pctChecker.RunCycle)
        {
            //标记为下一轮可以开始计数
            pctChecker.RunCount = 1;
            //runCount++;
            Console.WriteLine("成功标记下一次可以开始计数:" + pctChecker.RunCount);
        }
        else 
        {
            //如果是新的一轮
            //标记为下一轮可以开始计数
            pctChecker.RunCount = 1;
            Console.WriteLine("成功标记下一次可以开始计数:" + pctChecker.RunCount);

            //重置循环时间和零件加工时间为0
            pctChecker.RunStartTime = 0;

            //关闭新一轮开始按钮
            pctChecker.RunCycle = false;
        }
    }
    
    if (stauts == "运行中" && pctChecker.RunCount == 1) 
    {
        //设定只能修改一次,然后下一次零件加工开始时间刷新
        //首先设定程序的开始时间
        if (pctChecker.RunStartTime == 0) 
        {
            pctChecker.CountTime = 0;
            pctChecker.RunStartTime = currentTime;
        }


        //循环时间 = 当前时间 - 开始运行的时间
        pctChecker.CountTime = currentTime - pctChecker.RunStartTime;
        Console.WriteLine("成功进入查看循环时间:" + pctChecker.CountTime);
    }

    return ""+ pctChecker.CountTime;
}

/// <summary>
/// 获取运行状态
/// </summary>
string GetRunStatus(EZSockets.MitCom mitCom)
{
    int status;

    mitCom.GetRunStatus(1,out status);

    if (status == 0)
    {
        return "未运行";
    }
    else 
    {
        return "运行中";
    }
}

/// <summary>
/// 获取自启动时间
/// </summary>
string GetStartTime(EZSockets.MitCom mitCom)
{
    int plTime;

    mitCom.GetStartTime(out plTime);

    return plTime.ToString();
}

/// <summary>
/// 获取运行时间
/// </summary>
string GetRunTime(EZSockets.MitCom mitCom)
{
    int plTime;

    mitCom.GetRunTime(out plTime);

    return plTime.ToString();
}


/// <summary>
/// 获取NC系统报警
/// </summary>
string GetNCAlarm(EZSockets.MitCom mitCom)
{
    string[] alarmMsgs;
    string alarmMsg = "";
    mitCom.GetAlarm(out alarmMsgs);
    alarmMsg = "{ ";
    for (int i = 0; i < alarmMsgs.Length; i++)
    {
        if (alarmMsgs[i] != "" && alarmMsgs[i] != null)
        {
            alarmMsg = alarmMsg + alarmMsgs[i] + ", ";

        }

    }
    alarmMsg = alarmMsg + " }";
    return alarmMsg;
}

/// <summary>
/// 获取电源运行时间
/// </summary>
string GetAliveTime(EZSockets.MitCom mitCom)
{
    int plTime;

    mitCom.GetRunAliveTime(out plTime);

    if (plTime > 0)
    {
        return "在线";
    }
    else
    {
        return "离线";
    }
}

/// <summary>
/// 统计件数
/// </summary>
string GetCount(EZSockets.MitCom mitCom)
{
    string pvValue;
    mitCom.GetParaValue(30, 8002, 1, 1, out pvValue);
    return pvValue;
}

/// <summary>
/// 版本型号信息
/// </summary>
string GetVersion(EZSockets.MitCom mitCom)
{
    string version;
    mitCom.GetSimVersion(1, 0, out version);//获取版本
    return version;
}
#endregion
5.读取信息
①思路

​ --我们开启定时器进行读取

​ --然后判断表格读取的次数,如果是大于0,就说明表格已经读取过了数据

​ --那么就不会添加,而是进行修改了

②代码
#region 数据读取的方法群
//刷新UI界面的数据
private void btn_refresh_Click(object sender, EventArgs e)
{
    readData();
}


//读取需要的数据
int readCount = 0; //表格读取次数
public void readData()
{
    //获取连接IP的数据
    List<String> nodes = GetLinesFromTextBox(nodeNames);

    this.BeginInvoke((MethodInvoker)delegate ()
    {
        Console.WriteLine("表格读取次数:" + readCount);
        Console.WriteLine("表格行数:" + dataGridView1.RowCount);
        //如果
        if (readCount == 0 && dataGridView1.RowCount <= 1)
        {
            //清除表格行数据
            dataGridView1.Rows.Clear();
            for (int i = 0; i < nodes.Count; i++)
            {

                //,GetCount(mitComs[i])
                dataGridView1.Rows.Add(
                    GetVersion(mitComs[i]),
                    GetAliveTime(mitComs[i]),
                    GetCount(mitComs[i]),
                    GetNCAlarm(mitComs[i]),
                    GetRunTime(mitComs[i]),
                    GetRunStatus(mitComs[i]),
                    GetStartTime(mitComs[i]),
                    GetEstimateTime(mitComs[i], pctCheckers[i])
                    );
                readCount++;
            }
        }
        else
        {
            //清除表格行数据
            for (int i = 0; i < nodes.Count; i++)
            {
                // 更新已有行
                DataGridViewRow row = dataGridView1.Rows[i];
                row.Cells[0].Value = GetVersion(mitComs[i]);
                row.Cells[1].Value = GetAliveTime(mitComs[i]);
                row.Cells[2].Value = GetCount(mitComs[i]);
                row.Cells[3].Value = GetNCAlarm(mitComs[i]);
                row.Cells[4].Value = GetRunTime(mitComs[i]);
                row.Cells[5].Value = GetRunStatus(mitComs[i]);
                row.Cells[6].Value = GetStartTime(mitComs[i]);
                row.Cells[7].Value = GetEstimateTime(mitComs[i], pctCheckers[i]);

            }
        }
    });
}

//每秒执行的定时任务
private void timer2_Tick(object sender, EventArgs e)
{
    readData();
}

//开启读取按钮点击事件
private void readBtn_Click(object sender, EventArgs e)
{
    if (readBtn.Text == "开启读取")
    {
        //定时器开启
        refreshTimer.Enabled = true;
        readBtn.Text = "关闭读取";
        readFlag.Text = "开启";
    }
    else
    {
        refreshTimer.Enabled = false;
        readBtn.Text = "开启读取";
        readFlag.Text = "关闭";
    }
}
#endregion

发那科篇章

一、介绍

1.需要资料

​ 由于我将代码重构优化了,三菱和发那科都能一起采集了,你只要在网盘里面下载好三菱的资料就行了。三菱里面已经将发那科资料包含了,本篇就拿融合两个的代码,单独拎出来发那科的文章在这里讲解。

​ 这边我重新部署了一套集成两个采集的项目资料:项目首页 - 数据采集教程资料:数据采集资料 - GitCode

2.注意点
①属性设置

​ 需要设置属性,不然就报错:无法加载 DLL"FWLIB32.d":找不到指定的模块。

在这里插入图片描述

②生成平台

​ 需要设置生成平台,一定勾选 首选32位 因为dll是32位的,如果不勾选,就会报错:试图加载格式不正确的程序。

在这里插入图片描述

二、运行代码

1.调试设备

​ 这个大家可以先看看三菱的,调试步骤,这个都是共通的,等到设置设备IP的,大家再来看看下面这篇文章

​ 想要采集到数据就需要先调试好设备,因为我没有在现场,我就找了篇文章,大家自己看看就知道怎么开放设备的IP了

https://liuchuan.blog.youkuaiyun.com/article/details/142832669?fromshare=blogdetail&sharetype=blogdetail&sharerId=142832669&sharerefer=PC&sharesource=2203_75569939&sharefrom=from_link

2.运行软件

​ 这个步骤和三菱一样没什么区别,我就略过了

三、数据采集

1.代码了解

首先就是了解fwlib32.cs这个类,非常重要!这里详细讲

从图片里面大家也能看到里面结构,无非就算返回的数据对象

另外就是需要调用的方法了

在这里插入图片描述

2.参考手册

官方给的参考手册,官方都是英文的,这里pdf我给他翻译中文了,大家不收藏到时候可就找不到了,别花冤枉钱去翻译了。

然后这个TXT文档,我单独教大家怎么去提炼关键信息

在这里插入图片描述

3.提炼关键信息

假设你需要获得机器的运行状态,那么应该怎么找呢???

基本步骤:NCGuide.pdf文档 --》 FWLIBPM.TXT --》 代码方法完成

①找需要方法

OK,我们先打开NCGuide文档,因为我知道在哪里,所以我直接就把地方打开了

在这里插入图片描述

②看详细信息

因为这个和三菱略有不同,这个你在NCGuide里面只能找到方法是干嘛的,并没有详细说明

我们要去FWLIBPM.txt文档

打开后看到目录,因为状态相关信息方法,属于与他人相关功能方法的目录,也就是158页

在这里插入图片描述

怎么看你别怪我没讲怎么去看,其实你看看NCGuide文档目录结构就知道这个方法归属的目录了

为了效率不带大家了解了,直接Ctrl+F,输入NCGuide中的方法名称,就能快速定位过去

我用大框包住的就是你要填写的参数区域,里面内容我在图片中介绍了

在这里插入图片描述

4.代码实操

俗话说得好,实践出真理,单纯看完了,你可能脑子明白,但是你去问你手

手:看我干嘛!你脑子干了活,我手又没干,我咋知道

好了,我们直接上代码用注释讲解

	//存储当前类连接获得的句柄,我偷懒就直接公开了,大家要严格的话就自己写get方法
	public ushort Handle;	


	//连接方法,分配句柄
	public short Connect(string ip, ushort port, int timeout)
	{
    short ret = cnc_allclibhndl3(ip, port, timeout, out Handle);
    return ret;
	}

    //获取到运行状态
    public string get_run_status(int handle)
    {
        //未分配到句柄,那就是连接失败,就不用往下走了
        if (handle == 0)
        {
            return "停机中";
        }

        //这是数据结构体对象,对应着文档中信息
        ODBST ost = new ODBST();
        int ret = cnc_statinfo(Handle, ost);

        //Console.WriteLine("运行状态:"+ost.run);

        string runStatus = "未运行";

        switch (ost.run)
        {
            case 0:
                runStatus = "未运行";  // Reset
                break;
            case 1:
                runStatus = "暂停中";  // Stop
                break;
            case 2:
                runStatus = "保持中";  // Hold
                break;
            case 4:
                runStatus = "运行中"; // Start
                break;
            default:
                runStatus = "运行中"; // Unknown status
                break;
        }

        return runStatus;
    }

代码优化篇章

一、理解线程

1.UI线程
–作用

​ UI线程这个主要是用来更新界面UI的,里面最好不要放任何方法,只放对UI控件的属性数据的修改!!!

​ 其实UI线程就是主线程,主线程会来更新界面UI,所有不要写太多耗时代码在主线程,

​ 否则阻塞界面,导致界面卡顿。

–方法

​ invoke方法

            //这里有跨线程资源访问失败的问题,切换为主线程
            // 更新发那科的数据
            for (int i = iPList.mitNodes.Count; i < iPList.mitNodes.Count + iPList.fanucNodes.Count; i++)
            {
                //判断是否为主线程
                if (InvokeRequired)
                {
                    // 在主线程上执行获取和更新操作
                    this.Invoke(new Action(() =>
                    {
                        UpdateFanucData(i);
                    }));
                }
                else
                {
                    UpdateFanucData(i);
                }
            }

2.后台线程

​ 改为后台线程去计算,就不会影响前台页面的流程度,后台线程其实就是工作线程,如果你有静态的资源是在主线程创建的,

​ 那么恭喜你,成功的会在工作线程中拿取资源失败。

​ 常见的跨线程访问资源失败有:比如你在Task.Run(() => {这个里面写界面资源更新代码,那么恭喜你成功拿到报错信息,程序中断})

​ 上面的代码,其实就是我静态的对象,在主线程里面拿不到原来的那个静态对象了,只能在主线程里面拿到,于是我就切换回了主线程。

3.优化思路

​ 每5秒调用,新的一天就刷新表格读取状态,

​ 只调用状态方法,和报警信息,时间类的自增

​ 其他的不常常变化的只调用一次,减少了定时器频繁调用资源的弊端

二、优化后代码

1.总结代码
  • 初始化方法
  • 菜单配数方法
  • 连接进行方法
  • 数据读取方法
  • 相关界面变动方法
  • 其他工具方法
2.全部代码
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace SimCNC
{
    public partial class MultipleMitForm : Form
    {
        #region 初始化方法
        //--------------------------------------------
        //懒得写个对象数组了,大家想优化可以自己写
        List<MitDC> mitComs = new List<MitDC>();//模拟连接池
        List<FanucDC> fanucComs = new List<FanucDC>();//模拟连接池
        List<DeviceData> dataShows = new List<DeviceData>();//模拟连接池

        //零件加工循环时间判断类
        List<PartCycleTimeChecker> mitPctCheckers = new List<PartCycleTimeChecker>();//
        List<PartCycleTimeChecker> fanucPctCheckers = new List<PartCycleTimeChecker>();//
        //---------------------------------------------

        //连接的IPS对象管理
        ConnectIPList iPList = new ConnectIPList();

        //数据库连接字符串
        MysqlConfig config;
        private string connectionString = "";
        MySqlCRUD crud;
        public MultipleMitForm()
        {
            InitializeComponent();

            init();

            //初始化连接个数
            //默认初始化连接个数 10个
            connectionInit(10, 6);
        }

        public void init()
        {

            //设置列名
            dataGridView1.Columns.Clear();
            dataGridView1.Columns.Add("ips", "IP设备:");
            dataGridView1.Columns.Add("version", "版本信息:");
            dataGridView1.Columns.Add("aliveTime", "设备状态:");
            dataGridView1.Columns.Add("processCount", "零件加工总数:");
            dataGridView1.Columns.Add("waringMessage", "告警信息:");
            dataGridView1.Columns.Add("runTime", "运行时间:");
            dataGridView1.Columns.Add("runStatus", "运行状态:");
            dataGridView1.Columns.Add("CNCTime", "机床加工时间:");
            dataGridView1.Columns.Add("processTime", "目前零件加工时间:");
            // 设置列宽
            dataGridView1.Columns["processCount"].Width = 130; // 设置宽度为 100 像素
            dataGridView1.Columns["waringMessage"].Width = 150; // 设置宽度为 100 像素
            dataGridView1.Columns["CNCTime"].Width = 130; // 设置宽度为 100 像素
            dataGridView1.Columns["processTime"].Width = 150; // 设置宽度为 100 像素
            dataGridView1.AllowUserToAddRows = false;

            //设置禁止排序
            for (int i = 0; i < this.dataGridView1.Columns.Count; i++)
            {
                this.dataGridView1.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
            }


            //设置默认选中
            comboBox1.SelectedIndex = 0;
            //设置初始拥有IP地址
            iPTextBox.Text = "192.168.111.81\r\n192.168.111.82\r\n192.168.111.85\r\n192.168.111.86\r\n192.168.111.87\r\n192.168.111.88\r\n192.168.111.94\r\n192.168.111.95\r\n192.168.111.96\r\n192.168.111.97";

            //设置选项卡
            iPList.mitNodes = GetLinesFromString("192.168.111.81\r\n192.168.111.82\r\n192.168.111.85\r\n192.168.111.86\r\n192.168.111.87\r\n192.168.111.88\r\n192.168.111.94\r\n192.168.111.95\r\n192.168.111.96\r\n192.168.111.97");
            iPList.fanucNodes = GetLinesFromString("192.168.111.83\r\n192.168.111.89\r\n192.168.111.91\r\n192.168.111.92\r\n192.168.111.93\r\n192.168.111.98");

            //mysql配置信息类
            config = MysqlConfig.LoadFromJson("./配置文件/mysqlConfig.json"); ;


            //配置mysql数据库
            ReadMysqlConfig(config);

            //进行连接,初始化连接对象
            connectionString = "server=" + mysqlConnIP.Text + ";user=" + mysqlConnUser.Text + ";password=" + mysqlConnPass + ";database=" + mysqlConnDataBase + ";";
            crud = new MySqlCRUD(connectionString);
        }
        #endregion

        #region 菜单配置参数方法

        private int SendTimeCount()
        {
            int time = (Convert.ToInt32(dataSendCycleH.Text) * 60 * 60) + (Convert.ToInt32(dataSendCycleMin.Text) * 60) + Convert.ToInt32(dataSendCycleS.Text);
            int sendTime = time * 1000;
            Console.WriteLine("数据发送时间:" + sendTime);
            return sendTime;
        }

        //后续将配置改造为硬编码

        //定时发生方法数据修改事件
        private void ReadTimeUpdate_Method(object sender, EventArgs e)
        {

        }

        //测试数据库是否连接成功
        private void testConnectBtn_Click(object sender, EventArgs e)
        {
            try
            {
                connectionString = "server=" + mysqlConnIP.Text + ";user=" + mysqlConnUser.Text + ";password=" + mysqlConnPass + ";database=" + mysqlConnDataBase + ";";
                crud = new MySqlCRUD(connectionString);

                MessageBox.Show("连接成功");

            }
            catch (Exception ex)
            {
                MessageBox.Show("连接失败");
            }
        }

        //保存定时发送数据的配置
        private void 点击保存配置ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            WriteMysqlConfig(config, "./配置文件/mysqlConfig.json");
        }

        // 配置UI界面参数信息方法
        private void ReadMysqlConfig(MysqlConfig mc)
        {
            if (mc == null)
            {
                throw new ArgumentNullException(nameof(mc), "MysqlConfig cannot be null");
            }

            mysqlConnIP.Text = mc.Ip ?? string.Empty;                    // 设置IP
            mysqlConnPort.Text = mc.Port ?? string.Empty;                // 设置端口
            mysqlConnUser.Text = mc.User ?? string.Empty;                // 设置用户名
            mysqlConnPass.Text = mc.Password ?? string.Empty;            // 设置密码
            mysqlConnDataBase.Text = mc.Database ?? string.Empty;        // 设置数据库名
            mysqlSendStatus.Text = mc.MysqlSendStatus ?? string.Empty;   // 设置发送状态
            dataSendCycleS.Text = mc.DataSendCycleS ?? string.Empty;     // 设置秒发送周期
            dataSendCycleMin.Text = mc.DataSendCycleMin ?? string.Empty; // 设置分钟发送周期
            dataSendCycleH.Text = mc.DataSendCycleH ?? string.Empty;     // 设置小时发送周期
        }

        // 配置UI界面参数信息方法
        private void WriteMysqlConfig(MysqlConfig mc, string filePath)
        {
            if (mc == null)
            {
                throw new ArgumentNullException(nameof(mc), "MysqlConfig cannot be null");
            }

            mc.Ip = !string.IsNullOrEmpty(mysqlConnIP.Text) ? mysqlConnIP.Text : null;                    // 设置IP
            mc.Port = !string.IsNullOrEmpty(mysqlConnPort.Text) ? mysqlConnPort.Text : null;             // 设置端口
            mc.User = !string.IsNullOrEmpty(mysqlConnUser.Text) ? mysqlConnUser.Text : null;             // 设置用户名
            mc.Password = !string.IsNullOrEmpty(mysqlConnPass.Text) ? mysqlConnPass.Text : null;         // 设置密码
            mc.Database = !string.IsNullOrEmpty(mysqlConnDataBase.Text) ? mysqlConnDataBase.Text : null; // 设置数据库名
            mc.MysqlSendStatus = !string.IsNullOrEmpty(mysqlSendStatus.Text) ? mysqlSendStatus.Text : null;   // 设置发送状态
            mc.DataSendCycleS = !string.IsNullOrEmpty(dataSendCycleS.Text) ? dataSendCycleS.Text : null;     // 设置秒发送周期
            mc.DataSendCycleMin = !string.IsNullOrEmpty(dataSendCycleMin.Text) ? dataSendCycleMin.Text : null; // 设置分钟发送周期
            mc.DataSendCycleH = !string.IsNullOrEmpty(dataSendCycleH.Text) ? dataSendCycleH.Text : null;     // 设置小时发送周期

            //成功进入
            Console.WriteLine("成功进入配置改写!!!!            " + mc.User);

            mc.SaveToJson(filePath, mc);
        }

        #endregion

        #region 连接进行方法

        //初始化连接池
        public void connectionInit(int mitConneCount, int fanucConneCount)
        {
            //清空连接池
            mitComs.Clear();
            fanucComs.Clear();
            dataShows.Clear();

            //默认初始化连接个数 10个
            for (int i = 0; i < mitConneCount; i++)
            {
                MitDC mitCom = new MitDC();
                mitComs.Add(mitCom);

                PartCycleTimeChecker pctCheck = new PartCycleTimeChecker();
                mitPctCheckers.Add(pctCheck);

                DeviceData dataShow = new DeviceData();
                dataShows.Add(dataShow);
            }

            //默认初始化连接个数 6个
            for (int i = 0; i < fanucConneCount; i++)
            {
                FanucDC fanuc = new FanucDC();
                fanucComs.Add(fanuc);

                PartCycleTimeChecker pctCheck = new PartCycleTimeChecker();
                fanucPctCheckers.Add(pctCheck);

                DeviceData dataShow = new DeviceData();
                dataShows.Add(dataShow);
            }

            //Console.WriteLine("connectionInit方法修改完成后的连接池个数::" + mitComs.Count);
            //Console.WriteLine("connectionInit方法修改完成后的连接池个数::" + fanucComs.Count);
        }


        // 创建一个异步方法来处理连接
        /*async Task*/
        void ConnectDevicesAsync()
        {
            // 更新界面
            Application.DoEvents(); // 强制UI 刷新
            for (int i = 0; i < iPList.mitNodes.Count; i++)
            {
                // 连接三菱设备
                mitComs[i].GetSimConnect("M700M", "" + (i + 1), TimeOut.Text, iPList.mitNodes[i]);
                LoadConectLamp(iPList.mitNodes.Count + iPList.fanucNodes.Count, i);
                // 更新界面
                Application.DoEvents(); // 强制UI 刷新
            }


            for (int i = 0; i < iPList.fanucNodes.Count; i++)
            {
                // 初始化连接池的连接
                fanucComs[i].Connect(iPList.fanucNodes[i], 8193, Convert.ToInt32(TimeOut.Text));
                //Console.WriteLine("连接成功!!!!!:" + iPList.fanucNodes[i]);
                LoadConectLamp(iPList.mitNodes.Count + iPList.fanucNodes.Count, iPList.mitNodes.Count + i);
                // 更新界面
                Application.DoEvents(); // 强制UI 刷新
            }
        }


        public async void ConnectMethod()
        {
            string connStatus = Connect.Text;

            if (connStatus == "连接")
            {
                // 在调用处使用
                ConnectDevicesAsync();

                DataRetrieval();
            }


            if (connStatus == "断开")
            {
                for (int i = 0; i < iPList.mitNodes.Count; i++)
                {
                    //断开指定连接
                    //初始化连接池的连接
                    mitComs[i].GetSimConnect("M700M", "" + i + 1, TimeOut.Text, iPList.mitNodes[i]);//连接三菱设备

                    //初始化标记是否可以计数
                    mitPctCheckers[i] = new PartCycleTimeChecker();
                }


                for (int i = 0; i < iPList.fanucNodes.Count; i++)
                {
                    //断开指定连接
                    //初始化连接池的连接
                    fanucComs[i].DisConnect();

                    //初始化标记是否可以计数
                    fanucPctCheckers[i] = new PartCycleTimeChecker();
                }
            }
        }


        private void Connect_Click(object sender, EventArgs e)
        {
            LoadConectLamp(iPList.mitNodes.Count + iPList.fanucNodes.Count, 0);
            //设置奥特曼图片
            pictureBox1.Visible = true;

            //保存一下当前连接呀
            saveIps_Click(sender, e);

            //连接状态
            string connStatus = Connect.Text;

            //非空判断,IP输入数不合理判断
            if (iPList.mitNodes.Count < 1 && iPList.fanucNodes.Count < 1)
            {
                MessageBox.Show("请输入IP", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            //连接数判断 为false 就进入判断结束方法
            if (!connectionCountChanged())
            {
                return;
            }


            try
            {
                //Console.WriteLine("当前正在创建线程完成中1:");

                // 启动一个后台线程进行数据加载
                ConnectMethod();

                //改变界面属性方法
                formStatsChange(connStatus);

            }
            catch (Exception ex)
            {
                MessageBox.Show($" 连接/断开 过程中出现错误: {ex.Message}");
            }

        }

        //通用判断连接发生修改方法
        bool connectionCountChanged()
        {
            //Console.WriteLine("三菱连接池个数:" + mitComs.Count);
            //Console.WriteLine("三菱IP连接个数:" + iPList.mitNodes.Count);


            //Console.WriteLine("发那科连接池个数:" + fanucComs.Count);
            //Console.WriteLine("发那科IP连接个数:" + iPList.fanucNodes.Count);

            //优化后里面没有判断直接走通过
            bool flag = true;
            if (mitComs.Count != iPList.mitNodes.Count || fanucComs.Count != iPList.fanucNodes.Count)
            {
                crud.AddOrEditReset();//重置为新增状态
                crud.Delete();//删除旧代码
                Console.WriteLine("走了修改判断!!!!!!!!!!!!!!!!!!!!");
                connectionInit(iPList.mitNodes.Count, iPList.fanucNodes.Count);
            }

            return flag;
        }

        //窗体关闭前先关闭连接
        private void MultipleMitForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = false;

            DialogResult result = MessageBox.Show("关闭后数据推送将关闭,确定关闭吗?", "提示信息", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
            if (result == DialogResult.OK)
            {
                e.Cancel = false;  //点击OK

                //Console.WriteLine("窗口关闭前!!!!!!!!!!!!!!!!");
                if (Connect.Text == "断开")
                {
                    Connect_Click(sender, e);
                }
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void MultipleMitForm_FormClosed(object sender, FormClosedEventArgs e)
        {

            //Console.WriteLine("窗口关闭后!!!!!!!!!!!!!!!!");
            if (Connect.Text == "断开")
            {
                Connect_Click(sender, e);
            }

        }

        #endregion

        #region 数据读取方法

        //后台一直读取方法的运行状态(只要推送时开机的)


        //刷新UI界面的数据
        private void btn_refresh_Click(object sender, EventArgs e)
        {
            DataRetrieval();
        }

        //起飞传送门
        private async void mysqlSendTimer_Method(object sender, EventArgs e)
        {
            await dataSendMysql();
        }


        //轻量锁
        //private SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

        //定时刷新机器零件加工时间
        private void countTImer_Tick(object sender, EventArgs e)
        {
            /*Stopwatch sw = new Stopwatch();//Stopwatch提供一组方法和属性,可用于准确地测量运行时间
            sw.Start();
            timer2_Tick(sender,e);
            sw.Stop();
            TimeSpan dts = sw.Elapsed;//获取当前实例测量得出的总运行时间
            Console.WriteLine("timer2_Tick use time:{0}", dts);*/
            CountTime();
        }

        //起飞传送门
        private async void timer2_Tick(object sender, EventArgs e)
        {
            if (Connect.Text == "断开")
            {
                //异步方法影响效率
                /*await Task.Run(async () =>
                {*/
                //await _semaphore.WaitAsync(); // 等待信号量,确保只有一个线程可以进入
                try
                {
                    DataRetrieval();
                }
                finally
                {
                    //_semaphore.Release(); // 释放信号量
                }
                /*});*/
            }


        }

        async Task CountTime()
        {

            Stopwatch sw = new Stopwatch();//Stopwatch提供一组方法和属性,可用于准确地测量运行时间
            sw.Start();
            for (int i = 0; i < mitComs.Count; i++)
            {
                dataShows[i].ProcessTime = mitComs[i].GetEstimateTime(mitPctCheckers[i], dataShows[i].RunStatus, Convert.ToInt64(mitComs[i].GetStartTime()));
            }
            sw.Stop();
            TimeSpan dts = sw.Elapsed;//获取当前实例测量得出的总运行时间
            Console.WriteLine("零件加工计算时间 use time:{0}", dts);
        }

        //更新数据到数据库
        async Task dataSendMysql()
        {
            Console.WriteLine("设备数据已成功插入到数据库中!");

            var dataShowsCopy = dataShows.ToList(); // 创建集合副本

            await Task.Run(() =>
            {
                crud.AddOrEdit();

                foreach (var item in dataShowsCopy)
                {
                    crud.AddDeviceData(item);
                }

                foreach (var item in dataShowsCopy)
                {
                    crud.UpdateDeviceData(item);
                }
            });
        }

        async Task DataRetrieval()
        {
            Stopwatch sw = new Stopwatch();//Stopwatch提供一组方法和属性,可用于准确地测量运行时间
            sw.Start();

            Calculating(); // 在后台线程执行 Calculating
            if (readFlag.Text == "开启")
            {
                GetData(); // 执行获取数据
            }
            sw.Stop();
            TimeSpan dts = sw.Elapsed;//获取当前实例测量得出的总运行时间
            Console.WriteLine("DataRetrieval use time:{0}", dts);
        }


        //新增还是修改.0:新增,1:修改
        int addOrEdit = 0;

        public void Calculating()
        {
            Stopwatch sw = new Stopwatch();//Stopwatch提供一组方法和属性,可用于准确地测量运行时间
            sw.Start();

            // 添加三菱的数据
            for (int i = 0; i < iPList.mitNodes.Count; i++)
            {
                // 使用 mitComs 数组中的当前 MitCom 实例进行赋值
                dataShows[i].Ips = iPList.mitNodes[i]; // IP设备

                //不常常变化数据不参与修改,除非值为空
                if (addOrEdit == 0 || dataShows[i].Version == null || dataShows[i].Version == "")
                    dataShows[i].Version = mitComs[i].GetVersion(); // 版本信息

                dataShows[i].ProcessCount = mitComs[i].GetCount(); // 零件加工总数

                dataShows[i].WarningMessage = mitComs[i].GetNCAlarm(); // 告警信息

                dataShows[i].RunStatus = mitComs[i].GetRunStatus(); // 运行状态

                dataShows[i].AliveTime = dataShows[i].RunStatus == "停机中" ? "离线" : "在线"; // 设备状态

                dataShows[i].RunTime = mitComs[i].GetRunTime(); // 运行时间

                dataShows[i].CNCWorkTime = mitComs[i].GetStartTime(); // 机床加工时间 (假设这里是获取机床加工时间的调用,如果有不同的需要,请调整)

                //dataShows[i].ProcessTime = mitComs[i].GetEstimateTime(mitPctCheckers[i], dataShows[i].RunStatus, Convert.ToInt64(mitComs[i].GetStartTime())); // 目前零件加工时间
                //dataShows[i].ProcessTime = mitComs[i].GetEstimateTime(mitPctCheckers[i], dataShows[i].RunStatus); // 目前零件加工时间

            }

            //这里有跨线程资源访问失败的问题
            // 更新发那科的数据
            for (int i = iPList.mitNodes.Count; i < iPList.mitNodes.Count + iPList.fanucNodes.Count; i++)
            {
                // 在主线程上执行获取和更新操作
                if (InvokeRequired)
                {
                    this.Invoke(new Action(() =>
                    {
                        UpdateFanucData(i);
                    }));
                }
                else
                {
                    UpdateFanucData(i);
                }
            }


            sw.Stop();
            TimeSpan dts = sw.Elapsed;//获取当前实例测量得出的总运行时间
            Console.WriteLine("Calculating use time:{0}", dts);
        }


        // 主线程上的更新方法
        private void UpdateFanucData(int i)
        {
            long runTime = 0;
            double processTime = 0;
            try
            {
                // 尝试获取运行时间并进行转换
                string cycleTimeMin = fanucComs[i - iPList.mitNodes.Count].rd_para(6758); // 循环时间分钟
                string cycleTimeMes = fanucComs[i - iPList.mitNodes.Count].rd_para(6757); // 循环时间毫秒
                string runTimeMin = fanucComs[i - iPList.mitNodes.Count].rd_para(6752); // 运行时间分钟
                string runTimeMes = fanucComs[i - iPList.mitNodes.Count].rd_para(6751); // 运行时间毫秒

                // 验证并转换数据
                if (long.TryParse(cycleTimeMin, out long cycleTimeMinC) &&
                    long.TryParse(cycleTimeMes, out long cycleTimeMesC) &&
                    long.TryParse(runTimeMin, out long runTimeMinC) &&
                    long.TryParse(runTimeMes, out long runTimeMesC))
                {
                    runTime = (runTimeMinC * 60) + (runTimeMesC / 1000);
                    processTime = (cycleTimeMinC * 60) + (cycleTimeMesC / 1000);
                }
                else
                {
                    runTime = 0;
                    processTime = 0;
                }
            }
            catch (Exception ex)
            {
                runTime = 0;
                processTime = 0;
                Console.WriteLine($"Error parsing runTime: {ex.Message}");
            }

            // 更新已有数据列的值
            dataShows[i].Ips = iPList.fanucNodes[i - iPList.mitNodes.Count]; // IP设备
            if (addOrEdit == 0 || string.IsNullOrEmpty(dataShows[i].Version))
                dataShows[i].Version = fanucComs[i - iPList.mitNodes.Count].get_cnc_rdsyshard();
            dataShows[i].AliveTime = fanucComs[i - iPList.mitNodes.Count].GetHanlde() == 0 ? "离线" : "在线";
            dataShows[i].ProcessCount = fanucComs[i - iPList.mitNodes.Count].rd_para(6712);
            dataShows[i].WarningMessage = fanucComs[i - iPList.mitNodes.Count].get_alarm_state();
            dataShows[i].RunTime = runTime.ToString();
            dataShows[i].RunStatus = fanucComs[i - iPList.mitNodes.Count].get_run_status();
            dataShows[i].CNCWorkTime = runTime.ToString();
            dataShows[i].ProcessTime = processTime.ToString();
        }


        //读取需要的数据
        int GetReadCount = 0; //表格读取次数
        public void GetData()
        {
            Stopwatch sw = new Stopwatch();//Stopwatch提供一组方法和属性,可用于准确地测量运行时间
            sw.Start();

            //获取连接IP的数据
            //Console.WriteLine("DataTbale表格读取次数:" + GetReadCount);
            //Console.WriteLine("DataTable表格行数:" + (dataGridView1.Rows.Count));

            //确保两个数组里面有一个有值
            bool nullFlag = fanucComs.Count > 0 || mitComs.Count > 0;



            this.BeginInvoke((MethodInvoker)delegate ()
            {
                dataGridView1.SuspendLayout();
                //如果
                if (GetReadCount == 0 && nullFlag)
                {

                    // 清除表格行数据
                    dataGridView1.Rows.Clear();

                    // 添加三菱的数据
                    for (int i = 0; i < iPList.mitNodes.Count; i++)
                    {
                        // 添加行数据到 DataTable
                        dataGridView1.Rows.Add(
                            dataShows[i].Ips,
                            dataShows[i].Version,
                            dataShows[i].AliveTime,
                            dataShows[i].ProcessCount,
                            dataShows[i].WarningMessage,
                            dataShows[i].RunTime,
                            dataShows[i].RunStatus,
                            dataShows[i].CNCWorkTime,
                            dataShows[i].ProcessTime);
                    }

                    //添加发那科的数据
                    for (int i = iPList.mitNodes.Count; i < iPList.mitNodes.Count + iPList.fanucNodes.Count; i++)
                    {
                        //,GetCount(mitComs[i])
                        dataGridView1.Rows.Add(
                            dataShows[i].Ips,
                            dataShows[i].Version,
                            dataShows[i].AliveTime,
                            dataShows[i].ProcessCount,
                            dataShows[i].WarningMessage,
                            dataShows[i].RunTime,
                            dataShows[i].RunStatus,
                            dataShows[i].CNCWorkTime,
                            dataShows[i].ProcessTime);
                    }

                    GetReadCount = 1;
                }
                //又如果:表格的行数等于所有牌子IP地址所加的和 待优化为一个方法之后不用改动这里
                else if (dataGridView1.Rows.Count == iPList.mitNodes.Count + iPList.fanucNodes.Count)
                {
                    //更新三菱的数据
                    for (int i = 0; i < iPList.mitNodes.Count; i++)
                    {
                        // 假设 dataGridView1 是已经定义好的 DataTable
                        DataGridViewRow row = dataGridView1.Rows[i];
                        //row.Cells[0].Value = iPList.mitNodes[i];
                        row.Cells[1].Value = row.Cells[1].Value;
                        row.Cells[2].Value = row.Cells[2].Value;
                        row.Cells[3].Value = dataShows[i].ProcessCount;
                        row.Cells[4].Value = dataShows[i].WarningMessage;
                        row.Cells[5].Value = dataShows[i].RunTime;
                        row.Cells[6].Value = dataShows[i].RunStatus;
                        row.Cells[7].Value = dataShows[i].CNCWorkTime;
                        row.Cells[8].Value = dataShows[i].ProcessTime;
                    }

                    // 更新发那科的数据
                    int count = 0;
                    for (int i = iPList.mitNodes.Count; i < iPList.mitNodes.Count + iPList.fanucNodes.Count; i++)
                    {

                        // 假设 dt 是已经定义好的 DataTable
                        DataGridViewRow row = dataGridView1.Rows[i]; // 获取 DataTable 中的行

                        // 更新已有行的特定列的值
                        row.Cells[1].Value = row.Cells[1].Value;
                        row.Cells[2].Value = row.Cells[2].Value;
                        row.Cells[3].Value = dataShows[i].ProcessCount;
                        row.Cells[4].Value = dataShows[i].WarningMessage;
                        row.Cells[5].Value = dataShows[i].RunTime;
                        row.Cells[6].Value = dataShows[i].RunStatus;
                        row.Cells[7].Value = dataShows[i].CNCWorkTime;
                        row.Cells[8].Value = dataShows[i].ProcessTime;
                        count++;
                    }
                }

                dataGridView1.ResumeLayout(); // 恢复布局更新
            });

            sw.Stop();
            TimeSpan dts = sw.Elapsed;//获取当前实例测量得出的总运行时间
            //Console.WriteLine("function1 use time:{0}", dts);

        }
        #endregion

        #region 相关界面变动方法
        //开启或关闭数据推送
        private void dataSendStatus_Click(object sender, EventArgs e)
        {
            Console.WriteLine("成功点击开启");
            if (mysqlSendStatus.Text == "开启")
            {
                mysqlSendStatus.Text = "关闭";
                mysqlSendStatus.BackColor = Color.Red;
            }
            else
            {
                mysqlSendStatus.Text = "开启";
                mysqlSendStatus.BackColor = Color.LightGreen;
            }
        }
        //开启读取按钮点击事件
        private void readBtn_Click(object sender, EventArgs e)
        {
            if (readBtn.Text == "开启读取")
            {
                readBtn.Text = "关闭读取";
                readFlag.Text = "开启";
                readFlag.BackColor = Color.LightGreen;

                //refreshTimer.Enabled = true;
            }
            else
            {
                readBtn.Text = "开启读取";
                readFlag.Text = "关闭";
                readFlag.BackColor = Color.LightGray;

                //refreshTimer.Enabled = false;
            }
        }

        //界面属性根据连接和断开,界面需要发生变动方法
        public void formStatsChange(string connStatus)
        {
            this.BeginInvoke((MethodInvoker)delegate ()
            {
                try
                {
                    if (connStatus == "连接")
                    {
                        //连接状态禁止修改
                        iPTextBox.ReadOnly = true;

                        //将按钮设置可断开模式
                        Connect.Text = "断开";

                        //读取一下数据
                        this.readBtn.Text = "关闭读取";
                        readFlag.Text = "开启";
                        readFlag.BackColor = Color.LightGreen;

                        //开启定时器
                        refreshTimer.Start();
                        countTImer.Start();
                        mysqlSendTimer.Start();

                        //设置定时器时间
                        refreshTimer.Interval = Convert.ToInt32(readTimeBox.Text) * 1000;
                        mysqlSendTimer.Interval = SendTimeCount();

                        //清空按钮禁用
                        clearBtn.Enabled = false;
                    }

                    if (connStatus == "断开")
                    {
                        //关闭定时器
                        refreshTimer.Stop();
                        countTImer.Stop();
                        mysqlSendTimer.Stop();

                        //清除表格旧数据
                        GetReadCount = 0;
                        dataGridView1.Rows.Clear();

                        //连接状态禁止修改
                        iPTextBox.ReadOnly = false;

                        //将按钮设置可断开模式
                        Connect.Text = "连接";

                        //读取一下数据
                        this.readBtn.Text = "开启读取";
                        readFlag.Text = "关闭";
                        readFlag.BackColor = Color.LightGray;

                        //关闭进度灯
                        ClearConectLamp();

                        //清空按钮启用
                        clearBtn.Enabled = true;

                        //图片设置bukejian
                        pictureBox1.Visible = false;
                    }


                }
                catch (Exception ex)
                {
                    MessageBox.Show("发生错误:" + ex);
                }
            });
        }

        //保存按钮的方法,将填写数据存入对象数组
        private void saveIps_Click(object sender, EventArgs e)
        {
            //获取他当前选中的值
            int index = comboBox1.SelectedIndex;

            // 根据选中的值进行不同的处理
            switch (index)
            {
                case 0:
                    // 处理第一个选项
                    //Console.WriteLine("选中了第一个选项");
                    // 可以在这里添加相关逻辑
                    iPList.mitNodes = GetLinesFromString(iPTextBox.Text);
                    break;

                case 1:
                    // 处理第二个选项
                    //Console.WriteLine("选中了第二个选项");
                    // 可以在这里添加相关逻辑
                    iPList.fanucNodes = GetLinesFromString(iPTextBox.Text);
                    break;

                case 2:
                    // 处理第三个选项
                    //Console.WriteLine("选中了第三个选项");
                    // 可以在这里添加相关逻辑
                    iPList.attr1Nodes = GetLinesFromString(iPTextBox.Text);
                    break;

                default:
                    // 处理未选中或其他意外情况
                    //Console.WriteLine("未选中有效选项");
                    break;
            }
        }

        //处理选择不同品牌CNC机床的IP内容
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            //获取他当前选中的值
            int index = comboBox1.SelectedIndex;

            // 根据选中的值进行不同的处理
            switch (index)
            {
                case 0:
                    // 处理第一个选项
                    //Console.WriteLine("选中了第一个选项");
                    // 可以在这里添加相关逻辑
                    iPTextBox.Text = ConvertListToString(iPList.mitNodes);
                    break;

                case 1:
                    // 处理第二个选项
                    //Console.WriteLine("选中了第二个选项");
                    // 可以在这里添加相关逻辑
                    iPTextBox.Text = ConvertListToString(iPList.fanucNodes);
                    break;

                case 2:
                    // 处理第三个选项
                    //Console.WriteLine("选中了第三个选项");
                    // 可以在这里添加相关逻辑
                    iPTextBox.Text = ConvertListToString(iPList.attr1Nodes);
                    break;

                default:
                    // 处理未选中或其他意外情况
                    //Console.WriteLine("未选中有效选项");
                    break;
            }
        }


        //显示行号
        private void dataGridView1_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
        {
            e.Row.HeaderCell.Value = string.Format("{0}", e.Row.Index + 1);
        }

        //清空按钮
        private void clearBtn_Click(object sender, EventArgs e)
        {
            iPTextBox.Text = "";
        }

        //连接进度灯
        public async void LoadConectLamp(int total, int current)
        {
            //Console.WriteLine("加载灯的次数:" + (current + 1));
            //Console.WriteLine("加载灯的总数:" + (total));
            double schedule = (double)(current + 1) / total; // current + 1 代表已加载的灯的数量
            //Console.WriteLine("加载灯的进度:" + (schedule));
            if (schedule >= 0 && schedule < 0.1)
            {
                // schedule 在 [0, 0.1) 的代码块
                textBox1.BackColor = Color.LightGreen;
            }
            else if (schedule >= 0.1 && schedule < 0.2)
            {
                // schedule 在 [0.1, 0.2) 的代码块
                textBox2.BackColor = Color.GreenYellow;

            }
            else if (schedule >= 0.2 && schedule < 0.3)
            {
                // schedule 在 [0.2, 0.3) 的代码块
                textBox3.BackColor = Color.Yellow;
            }
            else if (schedule >= 0.3 && schedule < 0.4)
            {
                // schedule 在 [0.3, 0.4) 的代码块
                textBox4.BackColor = Color.Orange;
            }
            else if (schedule >= 0.4 && schedule < 0.5)
            {
                // schedule 在 [0.4, 0.5) 的代码块
                textBox5.BackColor = Color.OrangeRed;
            }
            else if (schedule >= 0.5 && schedule < 0.6)
            {
                // schedule 在 [0.5, 0.6) 的代码块
                textBox6.BackColor = Color.Red;
            }
            else if (schedule >= 0.6 && schedule < 0.7)
            {
                // schedule 在 [0.6, 0.7) 的代码块
                textBox7.BackColor = Color.LightPink;
            }
            else if (schedule >= 0.7 && schedule < 0.8)
            {
                // schedule 在 [0.7, 0.8) 的代码块
                textBox8.BackColor = Color.Blue;
            }
            else if (schedule >= 0.8 && schedule < 0.9)
            {
                // schedule 在 [0.8, 0.9) 的代码块
                textBox9.BackColor = Color.Purple;
            }
            else if (schedule >= 0.9 && schedule < 1)
            {
                // schedule 在 [0.9, 1) 的代码块
                textBox10.BackColor = Color.Cyan;
            }


        }

        // 关闭进度灯的方法
        public void ClearConectLamp()
        {
            // 将所有文本框的背景色恢复为默认颜色(例如白色)
            textBox1.BackColor = SystemColors.Window; // 默认为白色
            textBox2.BackColor = SystemColors.Window;
            textBox3.BackColor = SystemColors.Window;
            textBox4.BackColor = SystemColors.Window;
            textBox5.BackColor = SystemColors.Window;
            textBox6.BackColor = SystemColors.Window;
            textBox7.BackColor = SystemColors.Window;
            textBox8.BackColor = SystemColors.Window;
            textBox9.BackColor = SystemColors.Window;
            textBox10.BackColor = SystemColors.Window;

            //Console.WriteLine("所有指示灯已关闭。");
        }
        #endregion

        #region 其他工具方法
        // 方法:获取每行文本并填充数组
        private List<string> GetLinesFromString(string ips)
        {
            // 按行拆分字符串并移除空行
            List<string> lines = ips.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();

            // 返回包含每行文本的数组
            return lines;
        }

        // 方法:将 List<string> 转换为拼接字符串
        private static string ConvertListToString(List<string> ipList)
        {
            if (ipList == null)
            {
                return "";
            }
            // 使用 Join 方法将 List 中的字符串连接为一个多行字符串
            return string.Join(Environment.NewLine, ipList);
        }
        #endregion

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值