菜鸟上路啦!-我的第一个C# WinForm程序
本人是一个电气自动化工程师,却一直有一颗想成为程序员的心,觉得徜徉在代码的海洋里才是高大上的人生。无奈大学浑浑噩噩,没有好好学习编程知识,失去了成为了程序员的最好的机会。不过我发现既然是爱好,也不一定非要把它做成职业吧。再说这几天为了编这个程序,也真是日夜颠倒,神鬼不问了,可见新闻里报道的程序员经常猝死的事件真的是这个行业的特色了。
因为公司的业务需求,我们在调试系统过程中会得到大量的数据,需要进行处理与分析。将数据进行分类,生成图表,便于分析。之前我也用VBA在Excel中做过一个小工具,但是那个用起来还是比较原始的,刚好最近在网易云课堂上看了一个C#开发的视频课程,就萌生了自己做一个功能丰富一点的工具。
经过几天的奋战,找bug和修复bug的过程,这个小工具终于还是让我给做出来啦!俗话说好记性不如烂笔头,在做个程序的过程中确实学到了不少的知识点,但是如果我不把它总结记下来,可能过不了多久就会忘了,这也是我开始写这篇博客的原因。当然,如果我的这个博客能够给各位想要实现类似功能提供一点借鉴的话,我也是不胜自喜的。
程序界面
文件列表
原始数据样式
上图是这个工具的使用界面,由于审美能力有限,也只能做成这样了。下面对它的功能做一个简单介绍
- 打开文件并将文件中的数据分类显示在左侧的DataGridView里面
- 按下显示“DO-阀位曲线按钮”将DataGridView里面的日期,DO数据,DOSet数据,阀位数据生成折线图
- 按下显示“流量-压力曲线按钮”将DataGridView里面的日期,流量数据,压力数据生成折线图
- 添加范围线则在chart中基于当前的DOSet值进行±偏差值曲线显示
- 清除范围线将范围线删除
- 起始时间和结束时间可以动态选择曲线显示的时间段
- 鼠标在chart上移动显示相应的数值
- 坐标值设置输入框可以设置坐标轴的最大值和最小值
- 清除内容则将DataGridView里面的数据清空,同时Chart也清空
- 截屏并保存按钮自动将Chart显示的区域截屏并保存到文件
程序结构梳理
//控件事件
private void button1_OpenFile_Click(object sender, EventArgs e)//打开文件并显示
//控件事件
private void button2_ShowDO_StorkeCurves_Click(object sender, EventArgs e)//显示DO-阀位曲线
//控件事件
private void button3_ShowFlow_PressureCurves_Click(object sender, EventArgs e)//显示流量-压力曲线
//控件事件
private void textBox2_AiexXY_Set_TextChanged(object sender, EventArgs e)//修改坐标值
//控件事件
private void button5_ClearContext_Click(object sender, EventArgs e)//清除DataGridView内容及Chart初始化
//控件事件
private void dateTimePicker1_CloseUp(object sender, EventArgs e)//选择不同的时间段显示不同范围的曲线
//控件事件
private void button4_AddRangeLine_Click(object sender, EventArgs e)//添加偏差线
//控件事件
private void button1_ClearRangeLine_Click(object sender, EventArgs e)//清除偏差线
//控件事件
private void chart1_MouseMove(object sender, MouseEventArgs e)//鼠标移动显示实时数据值
//控件事件
private void button1_CopySCreen_Click(object sender, EventArgs e)//截图
//控件事件
private void button1_closewindows_Click(object sender, EventArgs e)//退出程序
//用户自定义程序
private List<string> LoadFileToList(string filepath)//将文件中的数据导入List
//用户自定义程序
private void ShowListInDataGridView(List<string> list)//将list里面的数据显示在DateGridView里面
//用户自定义程序
private List<double> GetSeriesList(List<string> list, int index)//获取不同的数据源List
//用户自定义程序
private List<DateTime> GetDateTimesList(List<string> list)//获取不同的时间List
// 用户自定义程序
private List<string> GetNewDateListByNewDateTime(DateTime newstartdatetime, DateTime newfinishdatetime)//通过设定的起始时间和结束时间得到新的NewDateList
//用户自定义程序
private void ChartInitialization()//Chart初始化
//用户自定义程序
private void SeriesSet(Series series, string legendtext, int borderwidth, AxisType axisType, SeriesChartType chartType)//设置Serie的属性
//用户自定义程序
private List<Double> GetDeviationPlusSeriesList(Double deviation,List<Double> serieslist)//获得正偏差list
//用户自定义程序
private List<Double> GetDeviationMinusSeriesList(Double deviation, List<Double> serieslist)//获得负偏差list
//用户自定义程序
private void ClearDeviationLine()//清除偏差线
//用户自定义程序
private void SaveImageFile(Image image)//保存图像文件
重点知识梳理
1. 如何打开文件
采用OpenFileDialog类的对象打开文件
string FileName = string.Empty;
OpenFileDialog openfile = new OpenFileDialog();
openfile.Filter = "CSV文件(*.csv)|*.csv|TXT文件(*.txt)|*.txt|所有文件(*.*)|*.*";
try
{
if (openfile.ShowDialog() == DialogResult.OK)//如果在打开文件弹窗中打开了文件
{
FileName = openfile.FileName;//获取打开文件的路径
}
catch (Exception ex)
{
MessageBox.Show("读取文件出现错误,具体错误如下" + ex.Message);
}
2.如何保存图像文件
采用SaveFileDialog对象保存文件
SaveFileDialog savefile = new SaveFileDialog();
string filename = string.Empty;
savefile.Filter = "JPG文件(*.jpg)|*.jpg";
if (savefile.ShowDialog() == DialogResult.OK)
{
filename = savefile.FileName;
image.Save(filename);
}
3.如何读取文件数据到List
采用StreamReader类对象的ReadLine()方法按行读取依次添加到list中
string line = string.Empty;
List<string> objlist = new List<string>();
StreamReader readfile = new StreamReader(filepath, Encoding.Default);
while ((line = readfile.ReadLine()) != null)
{
objlist.Add(line);
}
return objlist;
4.如何将list添加到DataGridView里面
3.1 先采用DataGridViewRow类对象的按照已存在的datagridview1对象用CreateCells创建单元格
3.2 再将list的每一个item按照 “,” 分割生成一个字符串数组
3.3 将字符串数组的元素赋值给相应的单元格
3.4 新建下一行
foreach (string item in list)
{
if (item.Contains("Datum"))
{
}
else
{
DataGridViewRow row = new DataGridViewRow();
row.CreateCells(dataGridView1);
string[] DataArray = item.Split(',');
row.Cells[0].Value = DataArray[0];
row.Cells[1].Value = DataArray[1];
row.Cells[2].Value = DataArray[3];
row.Cells[3].Value = DataArray[4];
row.Cells[4].Value = DataArray[5];
row.Cells[5].Value = DataArray[6];
row.Cells[6].Value = DataArray[7];
dataGridView1.Rows.Add(row);
}
}
5.如何让鼠标在曲线上移动时显示实时的值
//采用HitTestResult类对象
HitTestResult myTestResult = chart1.HitTest(e.X, e.Y);//申明一个撞击测试类的对象
if (myTestResult.ChartElementType == ChartElementType.DataPoint)//通过元素类型判断-DataPoint类型
{
this.Cursor = Cursors.Cross;//设置鼠标光标的形状为十字星
int i = myTestResult.PointIndex;//获取数据点的索引
DataPoint dp = myTestResult.Series.Points[i];//将该索引对应的数据点赋值给一个新建的DataPoint的对象
DateTime XValue = DateTime.FromOADate(dp.XValue);//获取该数据点对应的X坐标的值
Double YValue = dp.YValues[0];//获取该数据点对应的Y坐标的值
label4_XValue.Text= XValue.ToString();//将X坐标值赋值给一个Lable显示
label4_YValue.Text= YValue.ToString();//将Y坐标值赋值给一个Lable显示
label4_XValue.Visible = true;//设置lable可见
label4_YValue.Visible = true;//设置lable可见
}
else
{
this.Cursor = Cursors.Default;
label4_XValue.Visible = false;//设置lable不可见
label4_YValue.Visible = false;//设置lable不可见
}
6. 如何实现截屏
运用Graphics对象的CopyFromScreen方法,这里注意几点:
1.CopyFromScreen(Point 源矩形区域的左上角顶点的坐标,Point 目标矩形区域的左上角顶点的坐标,Size 矩形区域的面积)
源矩形区域—— 屏幕上的矩形区域
目标矩形区域——保存到的图形文件的矩形区域,这个值默认情况下应该为(0,0),
即表示将屏幕上截取的矩形区域的左上角顶点与待保存的图形文件的左上角顶点重合。
int width = chart1.Bounds.Width;
int height = chart1.Bounds.Height;
Image image = new Bitmap(width, height);//定义Image类对象
Graphics copyscreen = Graphics.FromImage(image);//定义Graphics类对象作为Image类对象的子对象
copyscreen.CopyFromScreen(this.PointToScreen(chart1.Location), new Point(0, 0), chart1.Size);//调用CopyFromScreen方法
SaveImageFile(image);//保存文件