C#工控上位机开发

对于电源软件开发者来说,上位机的开发难度是远远小于下位机的,之前几个月我一直在研究电力电子技术和下位机的控制算法,也有了一点点的收获,但说实话还是差的太远了,而且人力物力资源非常稀缺,为了做个负反馈控制实验还得自己掏钱买电机,到后来又发现负反馈电路还得专业人士搭建,示波器乱漆芭蕉的波形仿佛测的是自己的心电图,无奈。不过后续我会梳理一下这方面开发的学习心得,不得不说,整个电源的自主研发过程真的是道阻且长。

鲁迅先生曾经说过,柿子得挑软的捏,而且厂里确实也有需求,所以最近花了两周时间在开发工控上位机软件。虽说是个软柿子,但捏的确实不轻松(或许这就是弱者的世界吧T.T),不过不管怎么样,最终也是开发成功了,不枉我两周的爆肝。

那么废话不多说了,进入正题。

一.开发前的准备

(1)编程环境

我选用的编程环境是Vsual Studio 2019,之前在学linux操作系统时用过QTCreator,感觉两者也差不多,不过VS在制作窗体应用程序时采用的语言是C#,QT采用的是C++。C#是面向对象的,但语法上来看又是C,基本上懂C和C++的话,C#都能无师自通了。VS在官网上可以直接搜索下载,下载的教程也是比较丰富的,这里不做过多介绍。在选择工作负载时要确定好自己的设计目标,比如是进行游戏开发,还是网站开发,又或者是做个简单的窗体应用小程序,在进行窗体程序开发时是需要下载.netFramework框架的,框架已有多个版本,在确立好框架版本后你制作窗体软件的整个过程都是依赖于它的,(注意更新VS后,之前的框架可能会被删除,这个时候得去官网上找你之前的项目所依赖的.netFramework框架版本)。

因为是依赖于.netFramework框架的,因此很多底层的程序都是写完封装在类库里,只需要进行调用即可,当然开发过程中你也可以自己去写类库并进行添加和调用。

打开VS——>创建新项目——>搜索选择windows窗体应用(.netFramework)模板——>编辑项目名称,存储位置等——>创建,完成后会显示如下所示界面。

C#工控上位机开发_第1张图片

 在.cs[设计]中会有一个窗体,左边是工具箱,如果工具箱不见了可以按快捷键Ctrl+Alt+X,在工具箱中会有大量的控件,比如按钮,文本框,下拉框,进度条,定时器等等,制作时将该控件拖动到窗体中就行了,右边的属性就是你来对控件的操作,其实窗体也是个控件,因此上图的属性里就是对窗体进行设置,属性框里的闪电记号是事件的意思,当发生了某种事件时会执行的相应操作,可以通过双击某个事件进入.CS*的编程界面。那么窗体应用程序的整个开发也就是由这些基本的操作来展开的。

(2)下位机仿真

下位机采用的是西门子PLC,CPU型号是S7-1200,通信选择的是profinet通信协议。但控制板在工厂里的电源柜里使用中,实际的开发不可能跑现场去写一下运行一下。而想要进行完整的仿真我用到了两个软件,TIA Portal V16和S7-PLCSIM Advanced V3.0,前者为PLC控制板提供了编程环境,它本身可以当成一个PLC板,后者可以建立虚拟PLC与上位机的通信。

C#工控上位机开发_第2张图片

该图是TIA Portal V16某项目正在运行的界面。市面上的PLC控制板五花八门,每一种编程方式或者通信协议可能都不太一样,所以工控人多多少少有点难做,不过自主研发控制板就没那么纠结了,自产自销才是王道,毕竟学人家的完事儿了还得问人家买,典型的吃力不讨好。

下面说下TIA Portal V16打开后的一些操作。

  1. 创建一个新项目——>项目视图
  2. 添加一个CPU——>比如S7-1500
  3. CPU属性——>常规——>安全与防护——>允许远程访问
  4. 项目名——>属性——>保护——>允许块编译时仿真
  5. 程序块——>添加新块——>数据块
  6. 创建一个新数据类型后——>数据块——>属性——>常规——>属性——>取消所有勾选
  7. 工具下方的——>下载——>PC/PG接口(选择Siemens PLCSIM virtual Ethernet Adapter)——>开始搜索——>开始下载——>转至在线                            

在第七步下载之前需要打开PLCSIM仿真软件,否则在接口中是找不到想要的选项的。下图是进行配置时需要注意的一些事项:

C#工控上位机开发_第3张图片 C#工控上位机开发_第4张图片

首先是打开网络适配设置找到PLC的以太网,将IP地址改为与PLC处于同一网段的地址,然后在仿真软件里按如图所示进行连接,注意如果Online Acess选项中无法将按钮转至右侧,需要下载WinPcap,它可以提供网络接口。

在做好这些工作之后就可以通过编程来实现与PLC之间的数据通信了。

(3)数据库

数据库软件选择的是SQL Srever

SQL Server 2019 安装教程_SZU_黄其才-CSDN博客

这个博主写了详细的安装和配置细节。

C#工控上位机开发_第5张图片

 对数据库的所有操作都可以通过输入指令来完成(这也是为什么其他应用程序能够操作数据库的根本原因),当然能点击肯定还是点击方便,毕竟那些脚本指令也是挺多的,而且不太好记。因此可以很方便的通过点击去建立一个表并确定好各列的名称,对主键进行设置,是否允许控制,存储的数据类型等。

二.开发思路及代码详解

(1)实时显示系统时间

用到一个timer控件(工具箱组件里的,注意和日历控件区分)和一个label控件。Timer控件就是定时器,从功能来看类似于多线程的死循环,都拖入窗体后单击定时器在属性行为里把Enabled改为false,interval改成1000或者100也行,这代表它每100毫秒或是1000毫秒获取执行一次,(当然也可以在代码里进行更改,代码的优先级应该是高一点的吧)

private void timer1_Tick(object sender, EventArgs e)

        {

            label1.Text = DateTime.Now.ToString("yyyy年MM月dd日HH时mm分ss秒 ddd");

        }

执行的内容是将label1的文本内容进行方法(函数)返回值的赋值,该方法的作用是获取系统当前的时间并转化成字符串形式,如果要改成12小时制将HH改为hh即可,或者想以别的样式显示,但是某些特定的字符串在该方法中的显示出来的内容是固定的,比如ss返回的必然是系统的秒钟。

(2)连接PLC控制板

首先需要在VS添加一个程序包,操作方法是工具——>NuGet包管理器——>管理解决方案的程序包,在浏览中搜索S7netplus,安装

C#工控上位机开发_第6张图片

安装完成后在命名空间中引用 using S7.Net 即可(类似于添加头文件)

private Plc myplc;//实例化plc

private void radioButton5_CheckedChanged(object sender, EventArgs e)

        {

            if (radioButton5.Checked == true)

            {

                    myplc = new Plc(CpuType.S71200, "192.168.0.1", 0, 1);//Cpu型号,plc地址,机架号,插槽号

                    try

                    {

                        myplc.Open();

                    }

                    catch (Exception EX)

                    {

                        MessageBox.Show(EX.Message);

                    }

            }

        }

Try,catch语句用try来执行某个操作,当出现错误后catch执行某个操作,这里try的任务是与plc进行连接,出现错误的话,错误信息保存到变量EX中,由Messagebox(消息盒子)弹出错误信息。最外一层代表检测单选框的值是否改变,如果方式改变则触发事件,事件内容是判断单选按钮radiobutton5是否被选中,若被选中则打开(我在窗体加载事件中将该值赋值true,意味着一旦开始程序,plc就会打开)。

(3)文本框显示plc数据

首先这类文本框的作用是用来显示数据的,因此在相关属性中设置ReadOnly的值为true,这样用户就不可以对该文本框进行编辑了。

private void timer2_Tick(object sender, EventArgs e)

        {

            float c = ((uint)myplc.Read("DB1.DBD6.0")).ConvertToFloat();

            textBox1.Text = c.ToString();

        }

这里又用到了一个定时器,因为读取数据是一个循环往复的过程。Myplc.read是从plc读取数据,括号里参数的含义首先DB1代表是从编号为1的数据块读取的,DBD表示双字,其他的如DBW表示字,DBB表示字节,DBX表示位,6.0表示偏移量,由于在PLC中我们的数据是real型,也就是浮点型,转化的时候先转化为无符号整形(uint),再通过ConvertToFloat()方法转化为浮点型,定义一个浮点型变量c去保存这个数据,最后通过tostring方法将c保存的浮点型数据转化为字符串赋值给文本框内容。此外此次用到的布尔型数据转化方法bool a = (bool)myplc.Read("DB1.DBX4.0"),整形数据转化方法int a = (ushort)myplc.Read("DB1.DBW0.0")等等

(4)文本框写入plc数据

在实际操作过程中免不了要由用户输入值来控制plc的数据,比如我要设定一个输出电流值,或者打开某个开关,这都涉及到对plc中的数据进行写入。

private void textBox7_TextChanged(object sender, EventArgs e)

        {

           if (textBox7.Text == 1.ToString())

           {

               myplc.Write("DB1.DBD10.0",1);

           }

            else if(textBox7.Text == 2.ToString())

           {

              myplc.Write("DB1.DBD10.0", 2);

           }

            else

           {

             textBox7.Text = "";

MessageBox.Show("输入错误!");

             

           }

        }

因为不是最终版本,此段代码仅表示一个例子,myplc.write方法的两个参数分别表示数据块的地址和想要写入数据块的值,当输入的值为1时,把plc中该地址的值置1,当输入的值为2时,把plc中该地址的值置2,其他情况弹出弹窗表示输入错误。

(5)指示灯

关于指示灯其实一开始我是想找个相关的控件的,网上似乎也是有这种控件的,但后来发现是收费的,那就大可不必了。

private void timer2_Tick(object sender, EventArgs e)

        {

            float c = ((uint)myplc.Read("DB1.DBD6.0")).ConvertToFloat();

            textBox1.Text = c.ToString();

            if(c>2000)

            {

                pictureBox1.Image = Image.FromFile("C:\\Users\\DELL\\source\\图片素材\\微信图片_20211019080709.jpg");

            }

        }

C#工控上位机开发_第7张图片

 那么采用的方式是刷新picturebox控件的图片,在创建picturebox控件时可以在属性-外观-Image中导入初始图片,(这个图片的格式是否有限制还不太清除,不过就目前来看.jpg和.png类型的图片都可以导入)然后当某个变量的值到达某个点后更换该控件显示的图片,从而达到指示灯的作用,当然是否美观与导入的图片是有关联的,在调用Image.Fromfile方法时应注意地址格式。

(6)打开子窗体

前面说过,窗体本质上也是一个控件,不过添加方式不太一样。项目——>添加窗体(windows窗体)——>选择窗体并设置好名称即可。创建完该窗体后就可以通过其他窗体里的控件事件来打开该窗体了。

private void button2_Click(object sender, EventArgs e)

        {

            new Form2().Show();

        }

这是通过一个按钮的点击事件打开窗体的方法。

(7) 连接数据库及数据存储进数据库

在开发前的准备中已经将数据库配置好了,首先打开数据库并连接。在命名空间中引入数据库相关库文件

using System.Data.SqlClient;

private void timer3_Tick(object sender, EventArgs e)

        {

            SqlConnection connection = new SqlConnection();//新建连接对象

            connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

            connection.Open();

            string a = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            float c = ((uint)myplc.Read("DB1.DBD6.0")).ConvertToFloat();

            //添加数据库

            string strInsert = "INSERT INTO [dbo].[Table_1]([时间] ,[第一路输出电流],[第二路输出电流],[电压])VALUES('" + a + "','" + c.ToString() + "','" + c.ToString() + "','" + c.ToString() + "')";

            SqlCommand comm = new SqlCommand(strInsert, connection);

            try

            {

                int rc = comm.ExecuteNonQuery();

            }

            catch(Exception ex)

            {

               // MessageBox.Show(ex.Message);

            }  

            connection.Close();

        }

在这里又用到了一个定时器,因为数据是需要实时进行存储的。

第一句建一个名字叫connection的连接对象,

第二句是这个对象的连接字符串属性为(1.连接服务器时的服务器名称,打开数据库连接可以看到,2.连接的数据库的名字,3.连接安全性的设置吧,这点可照抄),

第三句打开这个对象,也就是打开数据库。

之前说过,对数据库的所有操作都有相应的脚本语句,因此定义了一个字符串strInsert来保存即将输入给数据库的脚本语句,语句的书写格式如代码所示,注意其中字符串的拼接。

Sqlcommond 建一个负责连接脚本指令的对象comm,sqlcommond方法里的参数分别是你要发送的指令和你的连接对象。在执行该语句后就相当于你已经在数据库中输入了该指令。如上文中的指令就是向数据库中的这些列插入某某变量的值,Sql server的脚本指令非常多,使用的时候需要根据具体需求去查,这里就不做汇总了。

下面try中定义了一个整型变量去接受comm.ExecuteNonQuery方法的返回值,该变量返回的值是受影响的行数,当返回的值为-1,说明输入的指令错误,不是insert型或是delete型或是updata型,因此在脚本指令不是这三种类型开头的情况下无法使用该方法去判断受影响的行数。但是有别的方法可以判断,在下面会讲到。

(8)实时曲线

这一部分是整个开发过程中最困难的一环,相当于一个低配版示波器。我本来应该分成几个部分来讲,但是代码中这几个部分绑在一起,干脆一并讲了。

首先曲线的话VS里是有自带的chart图表控件的,但是听说该控件的实时性不是很好,于是从网上下载了ZedGraph控件,搜索后在官网就能够下载,该控件是一个开源免费且功能强大的图表控件,你几乎可以使用它绘制出任何你想绘制的图表,下载完成后点击视图——工具箱——选择项——.Net Framework 组件——浏览——找到ZedGraph.dll并点击“打开”按钮,然后ZedGraphControl出现在.Net Framework 组件列表中——选中ZedGraphControl,然后点击“确定”按钮,即可在工具箱中看见ZedGraphControl控件。在使用该控件时有个非常难受的地方就是控件里的属性和事件全是英文,包括解释也是英文,所以英文不好用起来确实有点折磨。

同样的,引用该控件需要在命名控件引入控件相关库文件。

using ZedGraph;

  private void timer5_Tick (object sender, EventArgs e)

        {

            //曲线

            GraphPane panel = zgc.GraphPane;//控件声明

            PointPairList listAmp = new PointPairList();//电压曲线声明

            PointPairList listFreq = new PointPairList();//电流曲线声明

            LineItem cureAmp = panel.AddCurve("电压", listAmp, Color.Red, SymbolType.None);//电压曲线规格赋值

            LineItem cureFreq = panel.AddCurve("电流", listFreq, Color.Blue, SymbolType.None);//电流曲线规格赋值

            cureAmp.IsY2Axis = true; // 关联cureAmp曲线到右边的纵坐标轴

            //cureFreq.

            panel.Title.Text = "电压电流实时曲线";//标题

            panel.XAxis.Title.Text = "时间/s";//横坐标

            panel.YAxis.Title.Text = "电流/A";//纵坐标

            panel.Y2Axis.Title.Text = "电压/V";//纵坐标2   

            panel.Y2Axis.IsVisible = true;//纵坐标2显示使能

            panel.Title.FontSpec.Family = "Arial";//标题字体样式

            panel.Title.FontSpec.Size = 26;//标题字体大小

            panel.Title.FontSpec.IsBold = true;//标题字体粗体显示

            zgc.PanModifierKeys = Keys.Shift;//想用鼠标拖动坐标轴的话得按住shift

            zgc.IsEnableHPan = true; // 鼠标拖动时允许横向移动

            zgc.IsEnableVPan = true; // 鼠标拖动时允许纵向移动

            zgc.IsShowContextMenu = true;//鼠标右键菜单

            zgc.GraphPane.XAxis.MajorTic.IsOpposite = false;//上x轴大刻度禁止显示

            zgc.GraphPane.XAxis.MinorTic.IsOpposite = false;//上x轴小刻度禁止显示

            zgc.GraphPane.XAxis.MajorGrid.IsVisible = true; // 显示大刻度对应的网格

            zgc.GraphPane.XAxis.MinorGrid.IsVisible = true; // 显示小刻度对应的网格

            panel.XAxis.MajorGrid.DashOn = 5f;  // 网格为虚线,这句话是设置虚线中的实线部分长度

            panel.XAxis.MajorGrid.DashOff = 2f; // 设置虚线中的空白部分长度

            panel.XAxis.MajorGrid.PenWidth = 1.5f;   // 设置虚线线宽

            zgc.IsEnableVZoom = true// 纵轴允许缩放

            zgc.IsEnableHZoom = true;   // 横轴允许缩放

            zgc.ZoomStepFraction = 0.03; // 缩放速度

            zgc.IsShowCursorValues = true;

            panel.YAxis.Scale.BaseTic = 0;  // 纵坐标轴的起点从零开始

            panel.Y2Axis.Scale.BaseTic = 0; // 纵2坐标轴的起点从零开始

            panel.YAxis.Scale.Min = 0;//纵坐标最小值为0

            panel.YAxis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴的最大值

            panel.Y2Axis.Scale.Min = 0;///纵坐标2最小值为0

            panel.Y2Axis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴2的最大值

            panel.XAxis.Scale.MinAuto = false; // 根据数据自动匹配横坐标轴的最小值

            panel.XAxis.Scale.MaxAuto = true; // 根据数据自动匹配横坐标轴的最大值

            panel.XAxis.Scale.IsVisible = true; // 允许显示x轴刻度值

            panel.XAxis.Scale.MajorStepAuto = true;//大刻度自动匹配

            panel.XAxis.Scale.MinorStepAuto = true;//小刻度自动匹配

            panel.Fill = new Fill(Color.Yellow, Color.Pink, 45.0f); // 从左上角45.0°开始,从黄色过渡到粉色

            zgc.IsShowPointValues = true;//鼠标移动到某个点时显示该点坐标

            zgc.IsZoomOnMouseCenter = true;//以鼠标为中心进行放大

            SqlConnection connection = new SqlConnection();//新建连接对象

            connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

            connection.Open();

            string strSQL = "select top 600 * from Table_1 order by 时间 desc";//选择数据表数据的行数

            SqlCommand comm = new SqlCommand(strSQL, connection);

            SqlDataAdapter da = new SqlDataAdapter(strSQL, connection);

            DataSet ds = new DataSet();

            da.Fill(ds);

            dataGridView1.DataSource = ds.Tables[0];

            Double[] szy = new Double[dataGridView1.RowCount];//Y轴的数据数组

            string[] dates0 = new string[dataGridView1.RowCount];//制作string类型数组,这个数组存的是数据库最近保存的数据的时间信息

            for (int i =0; i <600; i++)//i表示行标

            {

                listAmp.Add(i, Convert.ToDouble(dataGridView1[3, 599-i].Value.ToString()));

                listFreq.Add(i, Convert.ToDouble(dataGridView1[3, 599 - i].Value.ToString())+1000);

                szy[i] = Convert.ToDouble(dataGridView1[3, 599-i].Value.ToString());

                dates0[i] = dataGridView1[0, 599-i].Value == null ? "" : dataGridView1[0,599-i].Value.ToString();

            }

            panel.XAxis.Type = AxisType.Text;//x轴选择为日期格式

            panel.XAxis.Scale.TextLabels = dates0;//数据显示格式为分秒  

            zgc.AxisChange(); // 因为点增加,需要自动修改横轴最大值(前提是MaxAuto为true),所以需要更新坐标

            Refresh(); // 把变化后的点集显示在图里

            connection.Close();

            panel.CurveList.Clear();//清除这次的曲线

        }

因为是实时曲线,因此整个函数也是封装在一个定时器里面的,每隔一秒刷新一次,注释基本都写了,下面讲一下注释没有提到的内容。首先是数据表控件DataGridView,上文已经实现了向数据库中写入数据了,那么从数据库中读取数据就需要用到数据表了,在连接数据库后向数据库写指令"select top 600 * from Table_1 order by 时间 desc",那么这句脚本指令是什么意思呢,它表示获取数据表中最近的600条数据,如果程序一直在运行,那么最近的600条数据其实就是最近600秒的数据,DataSet方法调用的是缓冲区数据,SqlDataAdapter类与SqlCommand类似,不过它针对的是缓冲区,因此算是后者的增强版,这里没有把SqlCommand屏蔽掉也没有影响。DataAdapter将数据从数据表拿到手保存到da中,ds用来表示缓冲区数据,然后da.Fill(ds)表示把da里的所有数据给到缓冲区,然后再由数据表读取出缓冲区数据。到现在我们就可以得到一个只显示最近600条数据的表格了,但是难点是如何将这写数据传达给曲线控件。其实想通了并不算复杂,首先我们是在一个定时器里,因此只需要将某一时刻的坐标值包括曲线确定下来,然后在末尾去加一个坐标轴更新和曲线清除,那么每次计时时都会重新进行绘制当下时刻的曲线,从而实现动态刷新,那么问题就转变成怎样将一个静态的数据导入到曲线控件中。ZedGraph控件是按照给的点然后连线完成曲线图的。我们定义两个数组去保存该时刻的变量,用一个Double型数组保存某一时刻y轴的点,用一个string类型的数组去保存同一时刻的时间数据,Rowcount代表行数,有多少行这个数组就存多少个数据。用一个for循环来将数组中的值赋给listXX.Add,我这里有两条曲线,因此将第二条曲线的y值+1000以区分,同时x轴的数据是不能直接赋值的,因为他是个时间数据,是个字符串,所以直接用i代替,然后在for循环下面一句对x轴的时间进行表现,但因为我时间数据过于详细,所以显示的点也是比较有限,dataGridview[,]数组里的两个数据分别是第几列和第几行的意思,599-i的原因是数据表中表头数据是最新时刻的数据,如果使用i那么x轴的时间就反过来显示了,最后因为是实时曲线,所以将该数据表隐藏了,在数据表控件属性-Visible改为false即可。

(8)选择起始时间和结束时间获取数据表信息和曲线

首先通过下拉框的形式由用户来确认可供选择的时间,这里是在窗体二加载过程中对下拉框内容的赋值过程。

private void Form2_Load(object sender, EventArgs e)

        {

            int i,j,k,l,m;

            for (i=2021;i<2041;i++)//

            {

                comboBox1.Items.Add(i.ToString());

                comboBox7.Items.Add(i.ToString());

            }

            for (j = 1; j < 10; j++)//

            {

                comboBox2.Items.Add('0'+j.ToString());

                comboBox8.Items.Add('0'+j.ToString());

            }

            for (j = 10; j < 13; j++)

            {

                comboBox2.Items.Add(j.ToString());

                comboBox8.Items.Add(j.ToString());

            }

            for (k = 1; k < 10; k++)//

            {

                comboBox3.Items.Add('0'+k.ToString());

                comboBox9.Items.Add('0'+k.ToString());

            }

            for(k=10;k<32;k++)

            {

                comboBox3.Items.Add(k.ToString());

                comboBox9.Items.Add(k.ToString());

            }

            for (l = 1; l < 10; l++)//

            {

                comboBox4.Items.Add('0'+l.ToString());

                comboBox10.Items.Add('0'+l.ToString());

            }

            for (l = 10; l < 25; l++)//

            {

                comboBox4.Items.Add(l.ToString());

                comboBox10.Items.Add(l.ToString());

            }

            for (m = 0; m < 10; m++)//分秒

            {

                comboBox5.Items.Add('0'+m.ToString());

                comboBox6.Items.Add('0'+m.ToString());

                comboBox11.Items.Add('0'+m.ToString());

                comboBox12.Items.Add('0'+m.ToString());

            }

            for (m = 10; m < 60; m++)//分秒

            {

                comboBox5.Items.Add(m.ToString());

                comboBox6.Items.Add(m.ToString());

                comboBox11.Items.Add(m.ToString());

                comboBox12.Items.Add(m.ToString());

            }

        }

下面就是由用户选择数据了,基本上是一些对用户输入数据是否正确的逻辑判断,首先判断是否是否有哪个框没选,然后判断两个时间的先后顺序是否正确,如果错误是哪个数据发生了错误,剩下的操作和实时曲线几乎差不多,有一点需要的注意到的,当用户输入的两个时间点的数据量非常庞大或者两个时间点间数据量非常小,那么数据表中的行数我们如何得知,因为这是由用户的输入来决定的,上面说过,comm.ExecuteNonQuery方法只能用来获取特定脚本输入的返回行,而现在对数据库的指令内容是获取并返回两个时间节点之间的所有数据,开头的脚本指令是Select,因此只能另谋他路。从数据库中读取多少行行不通,但是可以从数据表中想办法,在数据表被写入之前所有的数据都是存在于缓冲区的,这个时候我们可以直接对缓冲区的行数进行读取,定义一个整形变量count去保存dt.row.count就行,然后下面的for循环中i小于的值就是count。代码如下:

private void button1_Click(object sender, EventArgs e)

        {

            if(comboBox1.Text==""||comboBox2.Text==""||comboBox3.Text==""||comboBox4.Text==""||comboBox5.Text==""||comboBox6.Text==""||comboBox7.Text==""||comboBox8.Text==""||comboBox9.Text==""||comboBox10.Text==""||comboBox11.Text==""||comboBox12.Text=="")

            {

                MessageBox.Show("请将选取时间段设定完整!");

            }

            else

            {   

                if(Convert.ToInt32(comboBox1.Text)> Convert.ToInt32(comboBox7.Text))

                {

                    MessageBox.Show("年份顺序错误!请重新确立!");

                }

                else if(Convert.ToInt32(comboBox1.Text) < Convert.ToInt32(comboBox7.Text))

                {

                    SqlConnection connection = new SqlConnection();//新建连接对象

                    connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

                    connection.Open();

                    string strSQL = "select * from Table_1 where 时间>='" + comboBox1.Text + "-" + comboBox2.Text + "-" + comboBox3.Text + " " + comboBox4.Text + ":" + comboBox5.Text + ":" + comboBox6.Text + "' and 时间<='" + comboBox7.Text + "-" + comboBox8.Text + "-" + comboBox9.Text + " " + comboBox10.Text + ":" + comboBox11.Text + ":" + comboBox12.Text + "'";

                    SqlCommand comm = new SqlCommand(strSQL, connection);

                    SqlDataAdapter da = new SqlDataAdapter(strSQL, connection);

                    DataSet ds = new DataSet();

                    da.Fill(ds, "Table_1");

                    dataGridView1.DataSource = ds.Tables["Table_1"];

                    SqlDataAdapter dant = new SqlDataAdapter(comm);

                    DataTable dt = new DataTable();

                    dant.Fill(dt);

                    int count = dt.Rows.Count;

                    //曲线

                    GraphPane panel = zgc.GraphPane;//控件声明

                    PointPairList listAmp = new PointPairList();//电压曲线声明

                    PointPairList listFreq = new PointPairList();//电流曲线声明

                    LineItem cureAmp = panel.AddCurve("电压", listAmp, Color.Red, SymbolType.None);//电压曲线规格赋值

                    LineItem cureFreq = panel.AddCurve("电流", listFreq, Color.Blue, SymbolType.None);//电流曲线规格赋值

                    cureAmp.IsY2Axis = true; // 关联cureAmp曲线到右边的纵坐标轴

                                             //cureFreq.

                    panel.Title.Text = "电压电流实时曲线";//标题

                    panel.XAxis.Title.Text = "时间/s";//横坐标

                    panel.YAxis.Title.Text = "电流/A";//纵坐标

                    panel.Y2Axis.Title.Text = "电压/V";//纵坐标2   

                    panel.Y2Axis.IsVisible = true;//纵坐标2显示使能

                    panel.Title.FontSpec.Family = "Arial";//标题字体样式

                    panel.Title.FontSpec.Size = 26;//标题字体大小

                    panel.Title.FontSpec.IsBold = true;//标题字体粗体显示

                    zgc.PanModifierKeys = Keys.Shift;//想用鼠标拖动坐标轴的话得按住shift

                    zgc.IsEnableHPan = true; // 鼠标拖动时允许横向移动

                    zgc.IsEnableVPan = true; // 鼠标拖动时允许纵向移动

                    zgc.IsShowContextMenu = true;//鼠标右键菜单

                    zgc.GraphPane.XAxis.MajorTic.IsOpposite = false;//上x轴大刻度禁止显示

                    zgc.GraphPane.XAxis.MinorTic.IsOpposite = false;//上x轴小刻度禁止显示

                    zgc.GraphPane.XAxis.MajorGrid.IsVisible = true; // 显示大刻度对应的网格

                    zgc.GraphPane.XAxis.MinorGrid.IsVisible = true; // 显示小刻度对应的网格

                    panel.XAxis.MajorGrid.DashOn = 5f;  // 网格为虚线,这句话是设置虚线中的实线部分长度

                    panel.XAxis.MajorGrid.DashOff = 2f; // 设置虚线中的空白部分长度

                    panel.XAxis.MajorGrid.PenWidth = 1.5f;  // 设置虚线线宽

                    zgc.IsEnableVZoom = true;  // 纵轴允许缩放

                    zgc.IsEnableHZoom = true;   // 横轴允许缩放

                    zgc.ZoomStepFraction = 0.03; // 缩放速度

                    zgc.IsShowCursorValues = true;

                    panel.YAxis.Scale.BaseTic = 0;  // 纵坐标轴的起点从零开始

                    panel.Y2Axis.Scale.BaseTic = 0; // 纵2坐标轴的起点从零开始

                    panel.YAxis.Scale.Min = 0;//纵坐标最小值为0

                    panel.YAxis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴的最大值

                    panel.Y2Axis.Scale.Min = 0;///纵坐标2最小值为0

                    panel.Y2Axis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴2的最大值

                    panel.XAxis.Scale.MinAuto = false; // 根据数据自动匹配横坐标轴的最小值

                    panel.XAxis.Scale.MaxAuto = true; // 根据数据自动匹配横坐标轴的最大值

                    panel.XAxis.Scale.IsVisible = true; // 允许显示x轴刻度值

                    panel.XAxis.Scale.MajorStepAuto = true;//大刻度自动匹配

                    panel.XAxis.Scale.MinorStepAuto = true;//小刻度自动匹配

                    panel.Fill = new Fill(Color.Yellow, Color.Pink, 45.0f); // 从左上角45.0°开始,从黄色过渡到粉色

                    zgc.IsShowPointValues = true;//鼠标移动到某个点时显示该点坐标

                    zgc.IsZoomOnMouseCenter = true;//以鼠标为中心进行放大

                    Double[] szy = new Double[dataGridView1.RowCount];//Y轴的数据数组

                    string[] dates0 = new string[dataGridView1.RowCount];//制作string类型数组,这个数组存的是数据库最近保存的数据的时间信息

                    for (int i = 0; i < count; i++)//i表示行标

                    {

                        listAmp.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()));

                        listFreq.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()) + 1000);

                        szy[i] = Convert.ToDouble(dataGridView1[3,i].Value.ToString());

                        dates0[i] = dataGridView1[0,i].Value == null ? "" : dataGridView1[0,i].Value.ToString();

                    }

                    panel.XAxis.Type = AxisType.Text;//x轴选择为日期格式

                    panel.XAxis.Scale.TextLabels = dates0;//数据显示格式为分秒  

                    zgc.AxisChange(); // 因为点增加,需要自动修改横轴最大值(前提是MaxAuto为true),所以需要更新坐标

                    Refresh(); // 把变化后的点集显示在图里

                    connection.Close();

                }

                else

                {

                    if(Convert.ToInt32(comboBox2.Text)>Convert.ToInt32(comboBox8.Text))

                    {

                        MessageBox.Show("月份顺序错误!请重新确立!");

                    }

                    else if (Convert.ToInt32(comboBox2.Text) < Convert.ToInt32(comboBox8.Text))

                    {

                        SqlConnection connection = new SqlConnection();//新建连接对象

                        connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

                        connection.Open();

                        string strSQL = "select * from Table_1 where 时间>='" + comboBox1.Text + "-" + comboBox2.Text + "-" + comboBox3.Text + " " + comboBox4.Text + ":" + comboBox5.Text + ":" + comboBox6.Text + "' and 时间<='" + comboBox7.Text + "-" + comboBox8.Text + "-" + comboBox9.Text + " " + comboBox10.Text + ":" + comboBox11.Text + ":" + comboBox12.Text + "'";

                        SqlCommand comm = new SqlCommand(strSQL, connection);

                        //new Form4().Show();

                        SqlDataAdapter da = new SqlDataAdapter(strSQL, connection);

                        DataSet ds = new DataSet();

                        da.Fill(ds, "Table_1");

                        dataGridView1.DataSource = ds.Tables["Table_1"];

                        SqlDataAdapter dant = new SqlDataAdapter(comm);

                        DataTable dt = new DataTable();

                        dant.Fill(dt);

                        int count = dt.Rows.Count;

                        //曲线

                        GraphPane panel = zgc.GraphPane;//控件声明

                        PointPairList listAmp = new PointPairList();//电压曲线声明

                        PointPairList listFreq = new PointPairList();//电流曲线声明

                        LineItem cureAmp = panel.AddCurve("电压", listAmp, Color.Red, SymbolType.None);//电压曲线规格赋值

                        LineItem cureFreq = panel.AddCurve("电流", listFreq, Color.Blue, SymbolType.None);//电流曲线规格赋值

                        cureAmp.IsY2Axis = true; // 关联cureAmp曲线到右边的纵坐标轴

                                                 //cureFreq.

                        panel.Title.Text = "电压电流实时曲线";//标题

                        panel.XAxis.Title.Text = "时间/s";//横坐标

                        panel.YAxis.Title.Text = "电流/A";//纵坐标

                        panel.Y2Axis.Title.Text = "电压/V";//纵坐标2   

                        panel.Y2Axis.IsVisible = true;//纵坐标2显示使能

                        panel.Title.FontSpec.Family = "Arial";//标题字体样式

                        panel.Title.FontSpec.Size = 26;//标题字体大小

                        panel.Title.FontSpec.IsBold = true;//标题字体粗体显示

                        zgc.PanModifierKeys = Keys.Shift;//想用鼠标拖动坐标轴的话得按住shift

                        zgc.IsEnableHPan = true; // 鼠标拖动时允许横向移动

                        zgc.IsEnableVPan = true; // 鼠标拖动时允许纵向移动

                        zgc.IsShowContextMenu = true;//鼠标右键菜单

                        zgc.GraphPane.XAxis.MajorTic.IsOpposite = false;//上x轴大刻度禁止显示

                        zgc.GraphPane.XAxis.MinorTic.IsOpposite = false;//上x轴小刻度禁止显示

                        zgc.GraphPane.XAxis.MajorGrid.IsVisible = true; // 显示大刻度对应的网格

                        zgc.GraphPane.XAxis.MinorGrid.IsVisible = true; // 显示小刻度对应的网格

                        panel.XAxis.MajorGrid.DashOn = 5f;  // 网格为虚线,这句话是设置虚线中的实线部分长度

                        panel.XAxis.MajorGrid.DashOff = 2f; // 设置虚线中的空白部分长度

                        panel.XAxis.MajorGrid.PenWidth = 1.5f;  // 设置虚线线宽

                        zgc.IsEnableVZoom = true;  // 纵轴允许缩放

                        zgc.IsEnableHZoom = true;   // 横轴允许缩放

                        zgc.ZoomStepFraction = 0.03; // 缩放速度

                        zgc.IsShowCursorValues = true;

                        panel.YAxis.Scale.BaseTic = 0;  // 纵坐标轴的起点从零开始

                        panel.Y2Axis.Scale.BaseTic = 0; // 纵2坐标轴的起点从零开始

                        panel.YAxis.Scale.Min = 0;//纵坐标最小值为0

                        panel.YAxis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴的最大值

                        panel.Y2Axis.Scale.Min = 0;///纵坐标2最小值为0

                        panel.Y2Axis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴2的最大值

                        panel.XAxis.Scale.MinAuto = false; // 根据数据自动匹配横坐标轴的最小值

                        panel.XAxis.Scale.MaxAuto = true; // 根据数据自动匹配横坐标轴的最大值

                        panel.XAxis.Scale.IsVisible = true; // 允许显示x轴刻度值

                        panel.XAxis.Scale.MajorStepAuto = true;//大刻度自动匹配

                        panel.XAxis.Scale.MinorStepAuto = true;//小刻度自动匹配

                        panel.Fill = new Fill(Color.Yellow, Color.Pink, 45.0f); // 从左上角45.0°开始,从黄色过渡到粉色

                        zgc.IsShowPointValues = true;//鼠标移动到某个点时显示该点坐标

                        zgc.IsZoomOnMouseCenter = true;//以鼠标为中心进行放大

                        Double[] szy = new Double[dataGridView1.RowCount];//Y轴的数据数组

                        string[] dates0 = new string[dataGridView1.RowCount];//制作string类型数组,这个数组存的是数据库最近保存的数据的时间信息

                        for (int i = 0; i < count; i++)//i表示行标

                        {

                            listAmp.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()));

                            listFreq.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()) + 1000);

                            szy[i] = Convert.ToDouble(dataGridView1[3,i].Value.ToString());

                            dates0[i] = dataGridView1[0,i].Value == null ? "" : dataGridView1[0,i].Value.ToString();

                        }

                        panel.XAxis.Type = AxisType.Text;//x轴选择为日期格式

                        panel.XAxis.Scale.TextLabels = dates0;//数据显示格式为分秒  

                        zgc.AxisChange(); // 因为点增加,需要自动修改横轴最大值(前提是MaxAuto为true),所以需要更新坐标

                        Refresh(); // 把变化后的点集显示在图里

                        connection.Close();

                    }

                    else

                    {

                        if(Convert.ToInt32(comboBox3.Text)>Convert.ToInt32(comboBox9.Text))

                        {

                            MessageBox.Show("日期时间顺序错误!请重新确立!");

                        }

                        else if (Convert.ToInt32(comboBox3.Text) < Convert.ToInt32(comboBox9.Text))

                        {

                            SqlConnection connection = new SqlConnection();//新建连接对象

                            connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

                            connection.Open();

                            string strSQL = "select * from Table_1 where 时间>='" + comboBox1.Text + "-" + comboBox2.Text + "-" + comboBox3.Text + " " + comboBox4.Text + ":" + comboBox5.Text + ":" + comboBox6.Text + "' and 时间<='" + comboBox7.Text + "-" + comboBox8.Text + "-" + comboBox9.Text + " " + comboBox10.Text + ":" + comboBox11.Text + ":" + comboBox12.Text + "'";

                            SqlCommand comm = new SqlCommand(strSQL, connection);

                            //new Form4().Show();

                            SqlDataAdapter da = new SqlDataAdapter(strSQL, connection);

                            DataSet ds = new DataSet();

                            da.Fill(ds, "Table_1");

                            dataGridView1.DataSource = ds.Tables["Table_1"];

                            SqlDataAdapter dant = new SqlDataAdapter(comm);

                            DataTable dt = new DataTable();

                            dant.Fill(dt);

                            int count = dt.Rows.Count;

                            //曲线

                            GraphPane panel = zgc.GraphPane;//控件声明

                            PointPairList listAmp = new PointPairList();//电压曲线声明

                            PointPairList listFreq = new PointPairList();//电流曲线声明

                            LineItem cureAmp = panel.AddCurve("电压", listAmp, Color.Red, SymbolType.None);//电压曲线规格赋值

                            LineItem cureFreq = panel.AddCurve("电流", listFreq, Color.Blue, SymbolType.None);//电流曲线规格赋值

                            cureAmp.IsY2Axis = true; // 关联cureAmp曲线到右边的纵坐标轴

                                                     //cureFreq.

                            panel.Title.Text = "电压电流实时曲线";//标题

                            panel.XAxis.Title.Text = "时间/s";//横坐标

                            panel.YAxis.Title.Text = "电流/A";//纵坐标

                            panel.Y2Axis.Title.Text = "电压/V";//纵坐标2   

                            panel.Y2Axis.IsVisible = true;//纵坐标2显示使能

                            panel.Title.FontSpec.Family = "Arial";//标题字体样式

                            panel.Title.FontSpec.Size = 26;//标题字体大小

                            panel.Title.FontSpec.IsBold = true;//标题字体粗体显示

                            zgc.PanModifierKeys = Keys.Shift;//想用鼠标拖动坐标轴的话得按住shift

                            zgc.IsEnableHPan = true; // 鼠标拖动时允许横向移动

                            zgc.IsEnableVPan = true; // 鼠标拖动时允许纵向移动

                            zgc.IsShowContextMenu = true;//鼠标右键菜单

                            zgc.GraphPane.XAxis.MajorTic.IsOpposite = false;//上x轴大刻度禁止显示

                            zgc.GraphPane.XAxis.MinorTic.IsOpposite = false;//上x轴小刻度禁止显示

                            zgc.GraphPane.XAxis.MajorGrid.IsVisible = true; // 显示大刻度对应的网格

                            zgc.GraphPane.XAxis.MinorGrid.IsVisible = true; // 显示小刻度对应的网格

                            panel.XAxis.MajorGrid.DashOn = 5f;  // 网格为虚线,这句话是设置虚线中的实线部分长度

                            panel.XAxis.MajorGrid.DashOff = 2f; // 设置虚线中的空白部分长度

                            panel.XAxis.MajorGrid.PenWidth = 1.5f;  // 设置虚线线宽

                            zgc.IsEnableVZoom = true;  // 纵轴允许缩放

                            zgc.IsEnableHZoom = true;   // 横轴允许缩放

                            zgc.ZoomStepFraction = 0.03; // 缩放速度

                            zgc.IsShowCursorValues = true;

                            panel.YAxis.Scale.BaseTic = 0;  // 纵坐标轴的起点从零开始

                            panel.Y2Axis.Scale.BaseTic = 0; // 纵2坐标轴的起点从零开始

                            panel.YAxis.Scale.Min = 0;//纵坐标最小值为0

                            panel.YAxis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴的最大值

                            panel.Y2Axis.Scale.Min = 0;///纵坐标2最小值为0

                            panel.Y2Axis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴2的最大值

                            panel.XAxis.Scale.MinAuto = false; // 根据数据自动匹配横坐标轴的最小值

                            panel.XAxis.Scale.MaxAuto = true; // 根据数据自动匹配横坐标轴的最大值

                            panel.XAxis.Scale.IsVisible = true; // 允许显示x轴刻度值

                            panel.XAxis.Scale.MajorStepAuto = true;//大刻度自动匹配

                            panel.XAxis.Scale.MinorStepAuto = true;//小刻度自动匹配

                            panel.Fill = new Fill(Color.Yellow, Color.Pink, 45.0f); // 从左上角45.0°开始,从黄色过渡到粉色

                            zgc.IsShowPointValues = true;//鼠标移动到某个点时显示该点坐标

                            zgc.IsZoomOnMouseCenter = true;//以鼠标为中心进行放大

                            Double[] szy = new Double[dataGridView1.RowCount];//Y轴的数据数组

                            string[] dates0 = new string[dataGridView1.RowCount];//制作string类型数组,这个数组存的是数据库最近保存的数据的时间信息

                            for (int i = 0; i < count; i++)//i表示行标

                            {

                                listAmp.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()));

                                listFreq.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()) + 1000);

                                szy[i] = Convert.ToDouble(dataGridView1[3,i].Value.ToString());

                                dates0[i] = dataGridView1[0,i].Value == null ? "" : dataGridView1[0,i].Value.ToString();

                            }

                            panel.XAxis.Type = AxisType.Text;//x轴选择为日期格式

                            panel.XAxis.Scale.TextLabels = dates0;//数据显示格式为分秒  

                            zgc.AxisChange(); // 因为点增加,需要自动修改横轴最大值(前提是MaxAuto为true),所以需要更新坐标

                            Refresh(); // 把变化后的点集显示在图里

                            connection.Close();

                        }

                        else

                        {

                            if(Convert.ToInt32(comboBox4.Text)>Convert.ToInt32(comboBox10.Text))

                            {

                                MessageBox.Show("小时顺序错误!请重新确立!");

                            }

                            else if (Convert.ToInt32(comboBox4.Text) < Convert.ToInt32(comboBox10.Text))

                            {

                                SqlConnection connection = new SqlConnection();//新建连接对象

                                connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

                                connection.Open();

                                string strSQL = "select * from Table_1 where 时间>='" + comboBox1.Text + "-" + comboBox2.Text + "-" + comboBox3.Text + " " + comboBox4.Text + ":" + comboBox5.Text + ":" + comboBox6.Text + "' and 时间<='" + comboBox7.Text + "-" + comboBox8.Text + "-" + comboBox9.Text + " " + comboBox10.Text + ":" + comboBox11.Text + ":" + comboBox12.Text + "'";

                                SqlCommand comm = new SqlCommand(strSQL, connection);

                                //new Form4().Show();

                                SqlDataAdapter da = new SqlDataAdapter(strSQL, connection);

                                DataSet ds = new DataSet();

                                da.Fill(ds, "Table_1");

                                dataGridView1.DataSource = ds.Tables["Table_1"];

                                SqlDataAdapter dant = new SqlDataAdapter(comm);

                                DataTable dt = new DataTable();

                                dant.Fill(dt);

                                int count = dt.Rows.Count;

                                //曲线

                                GraphPane panel = zgc.GraphPane;//控件声明

                                PointPairList listAmp = new PointPairList();//电压曲线声明

                                PointPairList listFreq = new PointPairList();//电流曲线声明

                                LineItem cureAmp = panel.AddCurve("电压", listAmp, Color.Red, SymbolType.None);//电压曲线规格赋值

                                LineItem cureFreq = panel.AddCurve("电流", listFreq, Color.Blue, SymbolType.None);//电流曲线规格赋值

                                cureAmp.IsY2Axis = true; // 关联cureAmp曲线到右边的纵坐标轴

                                                         //cureFreq.

                                panel.Title.Text = "电压电流实时曲线";//标题

                                panel.XAxis.Title.Text = "时间/s";//横坐标

                                panel.YAxis.Title.Text = "电流/A";//纵坐标

                                panel.Y2Axis.Title.Text = "电压/V";//纵坐标2   

                                panel.Y2Axis.IsVisible = true;//纵坐标2显示使能

                                panel.Title.FontSpec.Family = "Arial";//标题字体样式

                                panel.Title.FontSpec.Size = 26;//标题字体大小

                                panel.Title.FontSpec.IsBold = true;//标题字体粗体显示

                                zgc.PanModifierKeys = Keys.Shift;//想用鼠标拖动坐标轴的话得按住shift

                                zgc.IsEnableHPan = true; // 鼠标拖动时允许横向移动

                                zgc.IsEnableVPan = true; // 鼠标拖动时允许纵向移动

                                zgc.IsShowContextMenu = true;//鼠标右键菜单

                                zgc.GraphPane.XAxis.MajorTic.IsOpposite = false;//上x轴大刻度禁止显示

                                zgc.GraphPane.XAxis.MinorTic.IsOpposite = false;//上x轴小刻度禁止显示

                                zgc.GraphPane.XAxis.MajorGrid.IsVisible = true; // 显示大刻度对应的网格

                                zgc.GraphPane.XAxis.MinorGrid.IsVisible = true; // 显示小刻度对应的网格

                                panel.XAxis.MajorGrid.DashOn = 5f;  // 网格为虚线,这句话是设置虚线中的实线部分长度

                                panel.XAxis.MajorGrid.DashOff = 2f; // 设置虚线中的空白部分长度

                                panel.XAxis.MajorGrid.PenWidth = 1.5f;  // 设置虚线线宽

                                zgc.IsEnableVZoom = true;  // 纵轴允许缩放

                                zgc.IsEnableHZoom = true;   // 横轴允许缩放

                                zgc.ZoomStepFraction = 0.03; // 缩放速度

                                zgc.IsShowCursorValues = true;

                                panel.YAxis.Scale.BaseTic = 0;  // 纵坐标轴的起点从零开始

                                panel.Y2Axis.Scale.BaseTic = 0; // 纵2坐标轴的起点从零开始

                                panel.YAxis.Scale.Min = 0;//纵坐标最小值为0

                                panel.YAxis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴的最大值

                                panel.Y2Axis.Scale.Min = 0;///纵坐标2最小值为0

                                panel.Y2Axis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴2的最大值

                                panel.XAxis.Scale.MinAuto = false; // 根据数据自动匹配横坐标轴的最小值

                                panel.XAxis.Scale.MaxAuto = true; // 根据数据自动匹配横坐标轴的最大值

                                panel.XAxis.Scale.IsVisible = true; // 允许显示x轴刻度值

                                panel.XAxis.Scale.MajorStepAuto = true;//大刻度自动匹配

                                panel.XAxis.Scale.MinorStepAuto = true;//小刻度自动匹配

                                panel.Fill = new Fill(Color.Yellow, Color.Pink, 45.0f); // 从左上角45.0°开始,从黄色过渡到粉色

                                zgc.IsShowPointValues = true;//鼠标移动到某个点时显示该点坐标

                                zgc.IsZoomOnMouseCenter = true;//以鼠标为中心进行放大

                                Double[] szy = new Double[dataGridView1.RowCount];//Y轴的数据数组

                                string[] dates0 = new string[dataGridView1.RowCount];//制作string类型数组,这个数组存的是数据库最近保存的数据的时间信息

                                for (int i = 0; i < count; i++)//i表示行标

                                {

                                    listAmp.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()));

                                    listFreq.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()) + 1000);

                                    szy[i] = Convert.ToDouble(dataGridView1[3,i].Value.ToString());

                                    dates0[i] = dataGridView1[0,i].Value == null ? "" : dataGridView1[0,i].Value.ToString();

                                }

                                panel.XAxis.Type = AxisType.Text;//x轴选择为日期格式

                                panel.XAxis.Scale.TextLabels = dates0;//数据显示格式为分秒  

                                zgc.AxisChange(); // 因为点增加,需要自动修改横轴最大值(前提是MaxAuto为true),所以需要更新坐标

                                Refresh(); // 把变化后的点集显示在图里

                                connection.Close();

                            }

                            else

                            {

                                if (Convert.ToInt32(comboBox5.Text) > Convert.ToInt32(comboBox11.Text))

                                {

                                    MessageBox.Show("分钟顺序错误!请重新确立!");

                                }

                                else if (Convert.ToInt32(comboBox5.Text) < Convert.ToInt32(comboBox11.Text))

                                {

                                    SqlConnection connection = new SqlConnection();//新建连接对象

                                    connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

                                    connection.Open();

                                    string strSQL = "select * from Table_1 where 时间>='" + comboBox1.Text + "-" + comboBox2.Text + "-" + comboBox3.Text + " " + comboBox4.Text + ":" + comboBox5.Text + ":" + comboBox6.Text + "' and 时间<='" + comboBox7.Text + "-" + comboBox8.Text + "-" + comboBox9.Text + " " + comboBox10.Text + ":" + comboBox11.Text + ":" + comboBox12.Text + "'";

                                    SqlCommand comm = new SqlCommand(strSQL, connection);

                                    //new Form4().Show();

                                    SqlDataAdapter da = new SqlDataAdapter(strSQL, connection);

                                    DataSet ds = new DataSet();

                                    da.Fill(ds, "Table_1");

                                    dataGridView1.DataSource = ds.Tables["Table_1"];

                                    SqlDataAdapter dant = new SqlDataAdapter(comm);

                                    DataTable dt = new DataTable();

                                    dant.Fill(dt);

                                    int count = dt.Rows.Count;

                                    //曲线

                                    GraphPane panel = zgc.GraphPane;//控件声明

                                    PointPairList listAmp = new PointPairList();//电压曲线声明

                                    PointPairList listFreq = new PointPairList();//电流曲线声明

                                    LineItem cureAmp = panel.AddCurve("电压", listAmp, Color.Red, SymbolType.None);//电压曲线规格赋值

                                    LineItem cureFreq = panel.AddCurve("电流", listFreq, Color.Blue, SymbolType.None);//电流曲线规格赋值

                                    cureAmp.IsY2Axis = true; // 关联cureAmp曲线到右边的纵坐标轴

                                                             //cureFreq.

                                    panel.Title.Text = "电压电流实时曲线";//标题

                                    panel.XAxis.Title.Text = "时间/s";//横坐标

                                    panel.YAxis.Title.Text = "电流/A";//纵坐标

                                    panel.Y2Axis.Title.Text = "电压/V";//纵坐标2   

                                    panel.Y2Axis.IsVisible = true;//纵坐标2显示使能

                                    panel.Title.FontSpec.Family = "Arial";//标题字体样式

                                    panel.Title.FontSpec.Size = 26;//标题字体大小

                                    panel.Title.FontSpec.IsBold = true;//标题字体粗体显示

                                    zgc.PanModifierKeys = Keys.Shift;//想用鼠标拖动坐标轴的话得按住shift

                                    zgc.IsEnableHPan = true; // 鼠标拖动时允许横向移动

                                    zgc.IsEnableVPan = true; // 鼠标拖动时允许纵向移动

                                    zgc.IsShowContextMenu = true;//鼠标右键菜单

                                    zgc.GraphPane.XAxis.MajorTic.IsOpposite = false;//上x轴大刻度禁止显示

                                    zgc.GraphPane.XAxis.MinorTic.IsOpposite = false;//上x轴小刻度禁止显示

                                    zgc.GraphPane.XAxis.MajorGrid.IsVisible = true; // 显示大刻度对应的网格

                                    zgc.GraphPane.XAxis.MinorGrid.IsVisible = true; // 显示小刻度对应的网格

                                    panel.XAxis.MajorGrid.DashOn = 5f;  // 网格为虚线,这句话是设置虚线中的实线部分长度

                                    panel.XAxis.MajorGrid.DashOff = 2f; // 设置虚线中的空白部分长度

                                    panel.XAxis.MajorGrid.PenWidth = 1.5f;  // 设置虚线线宽

                                    zgc.IsEnableVZoom = true;  // 纵轴允许缩放

                                    zgc.IsEnableHZoom = true;   // 横轴允许缩放

                                    zgc.ZoomStepFraction = 0.03; // 缩放速度

                                    zgc.IsShowCursorValues = true;

                                    panel.YAxis.Scale.BaseTic = 0;  // 纵坐标轴的起点从零开始

                                    panel.Y2Axis.Scale.BaseTic = 0; // 纵2坐标轴的起点从零开始

                                    panel.YAxis.Scale.Min = 0;//纵坐标最小值为0

                                    panel.YAxis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴的最大值

                                    panel.Y2Axis.Scale.Min = 0;///纵坐标2最小值为0

                                    panel.Y2Axis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴2的最大值

                                    panel.XAxis.Scale.MinAuto = false; // 根据数据自动匹配横坐标轴的最小值

                                    panel.XAxis.Scale.MaxAuto = true; // 根据数据自动匹配横坐标轴的最大值

                                    panel.XAxis.Scale.IsVisible = true; // 允许显示x轴刻度值

                                    panel.XAxis.Scale.MajorStepAuto = true;//大刻度自动匹配

                                    panel.XAxis.Scale.MinorStepAuto = true;//小刻度自动匹配

                                    panel.Fill = new Fill(Color.Yellow, Color.Pink, 45.0f); // 从左上角45.0°开始,从黄色过渡到粉色

                                    zgc.IsShowPointValues = true;//鼠标移动到某个点时显示该点坐标

                                    zgc.IsZoomOnMouseCenter = true;//以鼠标为中心进行放大

                                    Double[] szy = new Double[dataGridView1.RowCount];//Y轴的数据数组

                                    string[] dates0 = new string[dataGridView1.RowCount];//制作string类型数组,这个数组存的是数据库最近保存的数据的时间信息

                                    for (int i = 0; i < count; i++)//i表示行标

                                    {

                                        listAmp.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()));

                                        listFreq.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()) + 1000);

                                        szy[i] = Convert.ToDouble(dataGridView1[3,i].Value.ToString());

                                        dates0[i] = dataGridView1[0,i].Value == null ? "" : dataGridView1[0,i].Value.ToString();

                                    }

                                    panel.XAxis.Type = AxisType.Text;//x轴选择为日期格式

                                    panel.XAxis.Scale.TextLabels = dates0;//数据显示格式为分秒  

                                    zgc.AxisChange(); // 因为点增加,需要自动修改横轴最大值(前提是MaxAuto为true),所以需要更新坐标

                                    Refresh(); // 把变化后的点集显示在图里

                                    connection.Close();

                                }

                                else

                                {

                                    if(Convert.ToInt32(comboBox6.Text)>Convert.ToInt32(comboBox12.Text))

                                    {

                                        MessageBox.Show("秒钟顺序错误!请重新确立!");

                                    }

                                    else

                                    {

                                        SqlConnection connection = new SqlConnection();//新建连接对象

                                        connection.ConnectionString = "Data Source=DESKTOP-F57AF5E;Initial Catalog=Record;Integrated Security=SSPI;";//给连接对象指定连接的参数(连接字符串)

                                        connection.Open();

                                        string strSQL = "select * from Table_1 where 时间>='" + comboBox1.Text + "-" + comboBox2.Text + "-" + comboBox3.Text + " " + comboBox4.Text + ":" + comboBox5.Text + ":" + comboBox6.Text + "' and 时间<='" + comboBox7.Text + "-" + comboBox8.Text + "-" + comboBox9.Text + " " + comboBox10.Text + ":" + comboBox11.Text + ":" + comboBox12.Text + "'";

                                        SqlCommand comm = new SqlCommand(strSQL, connection);

                                        //new Form4().Show();

                                        SqlDataAdapter da = new SqlDataAdapter(strSQL, connection);

                                        DataSet ds = new DataSet();

                                        da.Fill(ds, "Table_1");

                                        dataGridView1.DataSource = ds.Tables["Table_1"];

                                        SqlDataAdapter dant = new SqlDataAdapter(comm);

                                        DataTable dt = new DataTable();

                                        dant.Fill(dt);

                                        int count = dt.Rows.Count;

                                        //曲线

                                        GraphPane panel = zgc.GraphPane;//控件声明

                                        PointPairList listAmp = new PointPairList();//电压曲线声明

                                        PointPairList listFreq = new PointPairList();//电流曲线声明

                                        LineItem cureAmp = panel.AddCurve("电压", listAmp, Color.Red, SymbolType.None);//电压曲线规格赋值

                                        LineItem cureFreq = panel.AddCurve("电流", listFreq, Color.Blue, SymbolType.None);//电流曲线规格赋值

                                        cureAmp.IsY2Axis = true; // 关联cureAmp曲线到右边的纵坐标轴

                                                                 //cureFreq.

                                        panel.Title.Text = "电压电流实时曲线";//标题

                                        panel.XAxis.Title.Text = "时间/s";//横坐标

                                        panel.YAxis.Title.Text = "电流/A";//纵坐标

                                        panel.Y2Axis.Title.Text = "电压/V";//纵坐标2   

                                        panel.Y2Axis.IsVisible = true;//纵坐标2显示使能

                                        panel.Title.FontSpec.Family = "Arial";//标题字体样式

                                        panel.Title.FontSpec.Size = 26;//标题字体大小

                                        panel.Title.FontSpec.IsBold = true;//标题字体粗体显示

                                        zgc.PanModifierKeys = Keys.Shift;//想用鼠标拖动坐标轴的话得按住shift

                                        zgc.IsEnableHPan = true; // 鼠标拖动时允许横向移动

                                        zgc.IsEnableVPan = true; // 鼠标拖动时允许纵向移动

                                        zgc.IsShowContextMenu = true;//鼠标右键菜单

                                        zgc.GraphPane.XAxis.MajorTic.IsOpposite = false;//上x轴大刻度禁止显示

                                        zgc.GraphPane.XAxis.MinorTic.IsOpposite = false;//上x轴小刻度禁止显示

                                        zgc.GraphPane.XAxis.MajorGrid.IsVisible = true; // 显示大刻度对应的网格

                                        zgc.GraphPane.XAxis.MinorGrid.IsVisible = true; // 显示小刻度对应的网格

                                        panel.XAxis.MajorGrid.DashOn = 5f;  // 网格为虚线,这句话是设置虚线中的实线部分长度

                                        panel.XAxis.MajorGrid.DashOff = 2f; // 设置虚线中的空白部分长度

                                        panel.XAxis.MajorGrid.PenWidth = 1.5f;  // 设置虚线线宽

                                        zgc.IsEnableVZoom = true;  // 纵轴允许缩放

                                        zgc.IsEnableHZoom = true;   // 横轴允许缩放

                                        zgc.ZoomStepFraction = 0.03; // 缩放速度

                                        zgc.IsShowCursorValues = true;

                                        panel.YAxis.Scale.BaseTic = 0;  // 纵坐标轴的起点从零开始

                                        panel.Y2Axis.Scale.BaseTic = 0; // 纵2坐标轴的起点从零开始

                                        panel.YAxis.Scale.Min = 0;//纵坐标最小值为0

                                        panel.YAxis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴的最大值

                                        panel.Y2Axis.Scale.Min = 0;///纵坐标2最小值为0

                                        panel.Y2Axis.Scale.MaxAuto = true; // 根据数据自动匹配纵坐标轴2的最大值

                                        panel.XAxis.Scale.MinAuto = false; // 根据数据自动匹配横坐标轴的最小值

                                        panel.XAxis.Scale.MaxAuto = true; // 根据数据自动匹配横坐标轴的最大值

                                        panel.XAxis.Scale.IsVisible = true; // 允许显示x轴刻度值

                                        panel.XAxis.Scale.MajorStepAuto = true;//大刻度自动匹配

                                        panel.XAxis.Scale.MinorStepAuto = true;//小刻度自动匹配

                                        panel.Fill = new Fill(Color.Yellow, Color.Pink, 45.0f); // 从左上角45.0°开始,从黄色过渡到粉色

                                        zgc.IsShowPointValues = true;//鼠标移动到某个点时显示该点坐标

                                        zgc.IsZoomOnMouseCenter = true;//以鼠标为中心进行放大

                                        Double[] szy = new Double[dataGridView1.RowCount];//Y轴的数据数组

                                        string[] dates0 = new string[dataGridView1.RowCount];//制作string类型数组,这个数组存的是数据库最近保存的数据的时间信息

                                        for (int i = 0; i < count; i++)//i表示行标

                                        {

                                            listAmp.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()));

                                            listFreq.Add(i, Convert.ToDouble(dataGridView1[3,i].Value.ToString()) + 1000);

                                            szy[i] = Convert.ToDouble(dataGridView1[3,i].Value.ToString());

                                            dates0[i] = dataGridView1[0,i].Value == null ? "" : dataGridView1[0,i].Value.ToString();

                                        }

                                        panel.XAxis.Type = AxisType.Text;//x轴选择为日期格式

                                        panel.XAxis.Scale.TextLabels = dates0;//数据显示格式为分秒  

                                        zgc.AxisChange(); // 因为点增加,需要自动修改横轴最大值(前提是MaxAuto为true),所以需要更新坐标

                                        Refresh(); // 把变化后的点集显示在图里

                                        connection.Close();

                                        //panel.CurveList.Clear();//清除这次的曲线

                                    }

                                }

                            }

                        }

                    }

                }

            }

               

        }

三.初步运行界面

C#工控上位机开发_第8张图片

C#工控上位机开发_第9张图片

你可能感兴趣的:(c#,sqlserver,嵌入式)