C#Windows窗体界面设计_攻击决策项目_03_数据绘图_01_绘制坐标轴_修订ParamsForm
2013-10-25 15:43
771 查看
Author: binzhouweichao@163.com
Copyright (c) 2013, Liu Xiaojian@BIT, All Rights Reserved.
Date: 2013-10-23
声明:本程序供参考;允许二次开发,但不允许在毫无更改的情况下占为己有。
沿用前面的序号。
7. 绘制坐标轴
pictrueBox1的横纵大小为610*610。
实际的雷区大小,为中心结点到雷结点的距离(Communication Range),加上各雷点的探测距离(Detection Range),然后再乘以2。
也就是说,确定了通信距离和探测距离后,实际的雷区宽高Width和Height就已经确定了。所以,修订ParamsForm中,关于雷区宽高的限制。
打开ParamsForm.cs[设计]文件,将雷点的TextBox和雷区的宽高的TextBox的ReadOnly属性设置为True。
7.1 设置ParamsForm的通信距离和检测距离的TextBox的回车事件
这两个文本框,按回车时触发下方的仿真场景的宽高变化。
7.1.1 首先,设置这两个文本框只能输入数字
自定义一个判断只能输入数字的函数。为了在其他地方也能使用这个函数,我们为项目添加一个新类,用于定义存放这些自定义函数。
为项目AttackDecision添加一个新类,命名为MyFunctions.cs。
为了方便调用,将类声明为静态类。即在类前加static修饰符。
为此类添加第一个静态成员方法,用于限定TextBox输入文本只能是数字,命名为NumberOnly。入口形参为KeyPressEventArgs类型,所以需要在文件头添加包含这个类的库,即using System.Windows.Forms;
函数体参考:http://wenku.baidu.com/view/be25fb300b4c2e3f57276345.html
修改后的MyFunctions.cs如下:
7.1.2 设置Communication Range文本框的KeyPress事件
选中CommunicationRange的TextBox,在右下方属性窗口中,选择事件属性,找到KeyPress事件,双击,自动生成mineCommunicationTextBox_KeyPress()事件函数,自动关联此文本框的回车按键触发事件。添加:
这样,此文本框只能输入数字(包含退格和回车),在点击回车之后,如果此文本非空,则使得下面的仿真场景的宽高值跟随变化。
7.1.3 同理,设置DetectionRange文本框的回车事件
7.1.4 顺便,设置一下AttackRange的文本框的KeyPress事件,只能输入数字
7.1.5 再顺便,修订一下OK按钮
当上述三个文本框中,有一个文本框的内容为空时,OK按钮失效。
当上述三个文本框未做修改时,OK按钮默认失效。
当上述三个文本框中,有任意一个做出修改时,OK按钮生效。
这样,首先设置OK按钮的默认属性Enabled为False。
打开ParamsForm.cs[设计]文件,选中OK按钮,在右侧的属性中,将Enabled的值改为False。
然后,再在上述三个TextBox的TextChanged事件函数中,添加判决OK按钮是否生效的语句。
后面的运算中需要用到仿真场景的宽高Text,为了防止在更改上述三个文本框后为按回车修改仿真场景的值,直接按了OK按钮,需要在OK按钮的Click事件函数中,重新设置一下仿真场景的宽高值,并将OK按钮禁用
7.2 设置坐标轴数据变量
在GlobalVars类中,设置绘制坐标轴使用的数据变量:
一个是绘图变量Bitmap bAxis,另一个是放大倍数float scaleTimes。
7.2.1 需要在GlobalVars.cs中,添加文件头using Drawings;。
7.2.2 自定义生成坐标轴BMP的函数
在MyFunctions.cs中,添加生成坐标轴BMP的函数,命名为CreateBAxis。
首先需要开放ParamsForm的仿真场景宽高TextBox的Text变量。
在ParamsForm.cs中,在构造函数下方添加开放部分私有控件属性:
其次,开放MainForm的pictureBox1的宽高属性。
在MainForm.cs中,在构造函数下方添加开放PictureBox1的宽高的只读属性:
回到MyFunctions.cs的CreateBAxis,因为用到绘图类,所以与GlobalVars相似,添加头文件using System.Drawing;。
7.2.3 然后,自定义显示坐标系函数
在MyFunctions中自定义函数AxisShow,用于显示生成的坐标轴。
需要开放MainForm的pictureBox1的Image写属性和Refresh()方法:
回到自定义函数:
7.2.4 修订MainForm的Load过程
在MainForm的Load过程中,就应当将坐标轴使用默认的值显示出来。
打开MainForm.cs[设计]文件,双击窗体,自动生成MainForm_Load()事件函数,自动关联MainForm的Load事件,添加:
7.2.5 修订ParamsForm的OK按钮
当点击OK按钮时,说明已经对宽高值做了修改(虽然AttackRange不影响),这时需要重绘坐标轴,在OK按钮的Click事件函数中,添加:
7.2.6 修订ParamsForm的Cancel按钮
当点击Cancel按钮时,对当前窗体,也就是ParamsForm窗体上,各TextBox所做的修改不生效,也就是说,设置一个全局变量,保存原先的值,点击Cancel按钮时,三个TextBox的值还原。
在GlobalVars类中,声明三个用于保存ParamsForm的TextBox的string类型全局变量:
这三个全局变量的初始值,应当在paramsForm初始化时就该赋上,我们把赋初值放在ParamsForm的Load事件函数中。
打开ParamsForm.cs[设计]文件,双击窗体,自动生成ParamsForm_Load()事件函数,自动关联此窗体的Load事件,添加初始化这三个值的代码:
然后回到ParamsForm的Cancel按钮的Click事件函数,添加使得三个TextBox还原的代码:
这样,当按OK按钮时,应当给这三个全局变量更新,在OK按钮的Click事件函数中,添加:
经过测试,当文本框文本改变时,TextChanged事件发生,会将OK按钮激活。所以在Cancel按钮的Click事件中,添加使得OK按钮失效的语句:
视图效果:
项目代码:
http://yunpan.cn/Q9AmY6HbSBzaI
注:下节会修订坐标轴,添加原点及标识,添加坐标轴箭头及表示,坐标轴虚线化。
Copyright (c) 2013, Liu Xiaojian@BIT, All Rights Reserved.
Date: 2013-10-23
声明:本程序供参考;允许二次开发,但不允许在毫无更改的情况下占为己有。
沿用前面的序号。
7. 绘制坐标轴
pictrueBox1的横纵大小为610*610。
实际的雷区大小,为中心结点到雷结点的距离(Communication Range),加上各雷点的探测距离(Detection Range),然后再乘以2。
也就是说,确定了通信距离和探测距离后,实际的雷区宽高Width和Height就已经确定了。所以,修订ParamsForm中,关于雷区宽高的限制。
打开ParamsForm.cs[设计]文件,将雷点的TextBox和雷区的宽高的TextBox的ReadOnly属性设置为True。
7.1 设置ParamsForm的通信距离和检测距离的TextBox的回车事件
这两个文本框,按回车时触发下方的仿真场景的宽高变化。
7.1.1 首先,设置这两个文本框只能输入数字
自定义一个判断只能输入数字的函数。为了在其他地方也能使用这个函数,我们为项目添加一个新类,用于定义存放这些自定义函数。
为项目AttackDecision添加一个新类,命名为MyFunctions.cs。
为了方便调用,将类声明为静态类。即在类前加static修饰符。
为此类添加第一个静态成员方法,用于限定TextBox输入文本只能是数字,命名为NumberOnly。入口形参为KeyPressEventArgs类型,所以需要在文件头添加包含这个类的库,即using System.Windows.Forms;
函数体参考:http://wenku.baidu.com/view/be25fb300b4c2e3f57276345.html
修改后的MyFunctions.cs如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace AttackDecision { static class MyFunctions { //7.1.1 限定TextBox只能输入数字,还包含退格和回车 public static void NumberOnly(ref KeyPressEventArgs e) { if ((e.KeyChar < 48 || e.KeyChar > 57) && (e.KeyChar != 13) && (e.KeyChar != 8))//数字0-9的ASCII码的范围,13为回车,8为退格 { e.Handled = true; } else { e.Handled = false; } } } }
7.1.2 设置Communication Range文本框的KeyPress事件
选中CommunicationRange的TextBox,在右下方属性窗口中,选择事件属性,找到KeyPress事件,双击,自动生成mineCommunicationTextBox_KeyPress()事件函数,自动关联此文本框的回车按键触发事件。添加:
//7.1.2 通信距离文本框回车事件 private void mineCommunicationTextBox_KeyPress(object sender, KeyPressEventArgs e) { MyFunctions.NumberOnly(ref e);//判断输入是否为数字(包括退格和回车) if (e.KeyChar == 13)//按回车执行下面的文本变换 { if (mineCommunicationTextBox.Text != "")//前提是此文本非空 { //仿真场景宽度为(通信距离+探测距离)*2 simulationWidthTextBox.Text = (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString(); //仿真场景高度与宽度相同 simulationHeightTextBox.Text = simulationWidthTextBox.Text; } } }
这样,此文本框只能输入数字(包含退格和回车),在点击回车之后,如果此文本非空,则使得下面的仿真场景的宽高值跟随变化。
7.1.3 同理,设置DetectionRange文本框的回车事件
//7.1.3 检测距离文本框的回车事件 private void mineDetectionTextBox_KeyPress(object sender, KeyPressEventArgs e) { MyFunctions.NumberOnly(ref e);//判断输入是否为数字(包括退格和回车) if (e.KeyChar == 13)//按回车执行下面的文本变换 { if (mineDetectionTextBox.Text != "")//前提是此文本非空 { //仿真场景宽度为(通信距离+探测距离)*2 simulationWidthTextBox.Text = (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString(); //仿真场景高度与宽度相同 simulationHeightTextBox.Text = simulationWidthTextBox.Text; } } }
7.1.4 顺便,设置一下AttackRange的文本框的KeyPress事件,只能输入数字
//7.1.4 攻击距离文本框限定只能为数字 private void mineAttackTextBox_KeyPress(object sender, KeyPressEventArgs e) { MyFunctions.NumberOnly(ref e);//判断输入是否为数字(包括退格和回车) }
7.1.5 再顺便,修订一下OK按钮
当上述三个文本框中,有一个文本框的内容为空时,OK按钮失效。
当上述三个文本框未做修改时,OK按钮默认失效。
当上述三个文本框中,有任意一个做出修改时,OK按钮生效。
这样,首先设置OK按钮的默认属性Enabled为False。
打开ParamsForm.cs[设计]文件,选中OK按钮,在右侧的属性中,将Enabled的值改为False。
然后,再在上述三个TextBox的TextChanged事件函数中,添加判决OK按钮是否生效的语句。
//7.1.5 判决OK按钮是否生效 private void mineCommunicationTextBox_TextChanged(object sender, EventArgs e) { if ((mineCommunicationTextBox.Text != "") && (mineDetectionTextBox.Text != "") && (mineAttackTextBox.Text != "")) { paramsSettingOkButton.Enabled = true; }//如果三个文本框均非空,使能OK按钮 else { paramsSettingOkButton.Enabled = false; }//否则,禁用OK按钮 } //同上 private void mineDetectionTextBox_TextChanged(object sender, EventArgs e) { if ((mineCommunicationTextBox.Text != "") && (mineDetectionTextBox.Text != "") && (mineAttackTextBox.Text != "")) { paramsSettingOkButton.Enabled = true; }//如果三个文本框均非空,使能OK按钮 else { paramsSettingOkButton.Enabled = false; }//否则,禁用OK按钮 } //同上 private void mineAttackTextBox_TextChanged(object sender, EventArgs e) { if ((mineCommunicationTextBox.Text != "") && (mineDetectionTextBox.Text != "") && (mineAttackTextBox.Text != "")) { paramsSettingOkButton.Enabled = true; }//如果三个文本框均非空,使能OK按钮 else { paramsSettingOkButton.Enabled = false; }//否则,禁用OK按钮 }
后面的运算中需要用到仿真场景的宽高Text,为了防止在更改上述三个文本框后为按回车修改仿真场景的值,直接按了OK按钮,需要在OK按钮的Click事件函数中,重新设置一下仿真场景的宽高值,并将OK按钮禁用
//4.2 OK按钮功能 private void paramsSettingOkButton_Click(object sender, EventArgs e) { this.Hide();//隐藏当前窗体 GlobalVars.mainForm.paramsSettingEnabled = true;//使能菜单Params Setting //7.1.5 重新设置一下仿真场景的宽高值 if(simulationWidthTextBox.Text != (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString()) { simulationWidthTextBox.Text = (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString(); simulationHeightTextBox.Text = simulationWidthTextBox.Text; } //7.1.5 禁用OK按钮 paramsSettingOkButton.Enabled = false; }
7.2 设置坐标轴数据变量
在GlobalVars类中,设置绘制坐标轴使用的数据变量:
一个是绘图变量Bitmap bAxis,另一个是放大倍数float scaleTimes。
7.2.1 需要在GlobalVars.cs中,添加文件头using Drawings;。
//7.2.1 坐标轴全局变量 //坐标轴BMP变量 private static Bitmap baxis; public static Bitmap bAxis { set { baxis = value; } get { return baxis; } } //放大倍数 private static float scaletimes; public static float scaleTimes { set { scaletimes = value; } get { return scaletimes; } }
7.2.2 自定义生成坐标轴BMP的函数
在MyFunctions.cs中,添加生成坐标轴BMP的函数,命名为CreateBAxis。
首先需要开放ParamsForm的仿真场景宽高TextBox的Text变量。
在ParamsForm.cs中,在构造函数下方添加开放部分私有控件属性:
//开放部分私有控件属性 //7.2.2 开放仿真场景宽高属性,只读 public string simulationWidth { get { return simulationWidthTextBox.Text; } } public string simulationHeight { get { return simulationHeightTextBox.Text; } }
其次,开放MainForm的pictureBox1的宽高属性。
在MainForm.cs中,在构造函数下方添加开放PictureBox1的宽高的只读属性:
//7.2.2 开放pictureBox1的宽高只读属性 public int pictureWidth { get { return pictureBox1.Width; } } public int pictureHeight { get { return pictureBox1.Height; } }
回到MyFunctions.cs的CreateBAxis,因为用到绘图类,所以与GlobalVars相似,添加头文件using System.Drawing;。
//7.2.2 生成坐标轴BMP public static void CreateBAxis() { //初始化坐标轴BMP实例,宽高为仿真场景的宽高 GlobalVars.bAxis = new Bitmap(GlobalVars.mainForm.pictureWidth, GlobalVars.mainForm.pictureHeight); //放大倍数 GlobalVars.scaleTimes = (float)GlobalVars.mainForm.pictureWidth / int.Parse(GlobalVars.mainForm.paramsForm.simulationWidth); //设置画板 Graphics gBAxis = Graphics.FromImage(GlobalVars.bAxis); //转换坐标系,原点为画布中心,右向x正向,上方为y正向 gBAxis.TranslateTransform((float)GlobalVars.mainForm.pictureWidth / 2, (float)GlobalVars.mainForm.pictureHeight / 2);//原点向右向下各平移图片大小的一半 gBAxis.ScaleTransform(GlobalVars.scaleTimes, (-1) * GlobalVars.scaleTimes);//放大,并且y反向 //设置画笔 Pen pBAxis = new Pen(Color.Blue, 1 / GlobalVars.scaleTimes); //设置绘图数据 PointF[] xAxis = new PointF[2]; xAxis[0].X = (float)(-1) * int.Parse( GlobalVars.mainForm.paramsForm.simulationWidth) / 2; xAxis[0].Y = 0F; xAxis[1].X = (float)int.Parse(GlobalVars.mainForm.paramsForm.simulationWidth) / 2; xAxis[1].Y = 0F; PointF[] yAxis = new PointF[2]; yAxis[0].X = 0F; yAxis[0].Y = (float)(-1) * int.Parse(GlobalVars.mainForm.paramsForm.simulationHeight) / 2; yAxis[1].X = 0F; yAxis[1].Y = (float)int.Parse(GlobalVars.mainForm.paramsForm.simulationHeight) / 2; PointF oAxis = new PointF(); oAxis.X = 0F; oAxis.Y = 0F; //绘制x轴 gBAxis.DrawLines(pBAxis, xAxis); //绘制y轴 gBAxis.DrawLines(pBAxis, yAxis); //绘制原点 // //释放资源 pBAxis.Dispose(); gBAxis.Dispose(); }
7.2.3 然后,自定义显示坐标系函数
在MyFunctions中自定义函数AxisShow,用于显示生成的坐标轴。
需要开放MainForm的pictureBox1的Image写属性和Refresh()方法:
//7.2.3 开放pictureBox1的Image的写属性 public Image pictureImage { set { pictureBox1.Image = value; } } //7.2.3 开放pictureBox的Refresh()方法 public void pictureRefresh() { pictureBox1.Refresh(); }
回到自定义函数:
//7.2.3 显示坐标轴 public static void AxisShow() { GlobalVars.mainForm.pictureImage = GlobalVars.bAxis; GlobalVars.mainForm.pictureRefresh(); }
7.2.4 修订MainForm的Load过程
在MainForm的Load过程中,就应当将坐标轴使用默认的值显示出来。
打开MainForm.cs[设计]文件,双击窗体,自动生成MainForm_Load()事件函数,自动关联MainForm的Load事件,添加:
//7.2.4 使用默认值显示坐标轴 private void MainForm_Load(object sender, EventArgs e) { MyFunctions.CreateBAxis(); MyFunctions.AxisShow(); }
7.2.5 修订ParamsForm的OK按钮
当点击OK按钮时,说明已经对宽高值做了修改(虽然AttackRange不影响),这时需要重绘坐标轴,在OK按钮的Click事件函数中,添加:
//4.2 OK按钮功能 private void paramsSettingOkButton_Click(object sender, EventArgs e) { this.Hide();//隐藏当前窗体 GlobalVars.mainForm.paramsSettingEnabled = true;//使能菜单Params Setting //7.1.5 重新设置一下仿真场景的宽高值 if(simulationWidthTextBox.Text != (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString()) { simulationWidthTextBox.Text = (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString(); simulationHeightTextBox.Text = simulationWidthTextBox.Text; } //7.1.5 禁用OK按钮 paramsSettingOkButton.Enabled = false; //7.2.5 重绘坐标轴 MyFunctions.CreateBAxis(); MyFunctions.AxisShow(); }
7.2.6 修订ParamsForm的Cancel按钮
当点击Cancel按钮时,对当前窗体,也就是ParamsForm窗体上,各TextBox所做的修改不生效,也就是说,设置一个全局变量,保存原先的值,点击Cancel按钮时,三个TextBox的值还原。
在GlobalVars类中,声明三个用于保存ParamsForm的TextBox的string类型全局变量:
//7.2.6 ParamsForm上三个TextBox的生效值 private static string pcomrangetext; public static string pComRangeText { set { pcomrangetext = value; } get { return pcomrangetext; } } private static string pdetrangetext; public static string pDetRangeText { set { pdetrangetext = value; } get { return pdetrangetext; } } private static string pattrangetext; public static string pAttRangeText { set { pattrangetext = value; } get { return pattrangetext; } }
这三个全局变量的初始值,应当在paramsForm初始化时就该赋上,我们把赋初值放在ParamsForm的Load事件函数中。
打开ParamsForm.cs[设计]文件,双击窗体,自动生成ParamsForm_Load()事件函数,自动关联此窗体的Load事件,添加初始化这三个值的代码:
//7.2.6 初始化赋值三个TextBox的默认值 private void ParamsForm_Load(object sender, EventArgs e) { GlobalVars.pComRangeText = this.mineCommunicationTextBox.Text; GlobalVars.pDetRangeText = this.mineDetectionTextBox.Text; GlobalVars.pAttRangeText = this.mineAttackTextBox.Text; }
然后回到ParamsForm的Cancel按钮的Click事件函数,添加使得三个TextBox还原的代码:
//4.3 Cancel按钮功能 private void paramsSettingCancelButton_Click(object sender, EventArgs e) { this.Hide();//隐藏当前窗体 GlobalVars.mainForm.paramsSettingEnabled = true;//使能菜单Params Setting //7.2.6 还原三个TextBox的值 this.mineCommunicationTextBox.Text = GlobalVars.pComRangeText; this.mineDetectionTextBox.Text = GlobalVars.pDetRangeText; this.mineAttackTextBox.Text = GlobalVars.pAttRangeText; }
这样,当按OK按钮时,应当给这三个全局变量更新,在OK按钮的Click事件函数中,添加:
//4.2 OK按钮功能 private void paramsSettingOkButton_Click(object sender, EventArgs e) { this.Hide();//隐藏当前窗体 GlobalVars.mainForm.paramsSettingEnabled = true;//使能菜单Params Setting //7.1.5 重新设置一下仿真场景的宽高值 if(simulationWidthTextBox.Text != (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString()) { simulationWidthTextBox.Text = (2 * (int.Parse(mineCommunicationTextBox.Text) + int.Parse(mineDetectionTextBox.Text))).ToString(); simulationHeightTextBox.Text = simulationWidthTextBox.Text; } //7.1.5 禁用OK按钮 paramsSettingOkButton.Enabled = false; //7.2.5 重绘坐标轴 MyFunctions.CreateBAxis(); MyFunctions.AxisShow(); //7.2.6 更新三个TextBox的缓存全局变量 GlobalVars.pComRangeText = this.mineCommunicationTextBox.Text; GlobalVars.pDetRangeText = this.mineDetectionTextBox.Text; GlobalVars.pAttRangeText = this.mineAttackTextBox.Text; }
经过测试,当文本框文本改变时,TextChanged事件发生,会将OK按钮激活。所以在Cancel按钮的Click事件中,添加使得OK按钮失效的语句:
//4.3 Cancel按钮功能 private void paramsSettingCancelButton_Click(object sender, EventArgs e) { this.Hide();//隐藏当前窗体 GlobalVars.mainForm.paramsSettingEnabled = true;//使能菜单Params Setting //7.2.6 还原三个TextBox的值 this.mineCommunicationTextBox.Text = GlobalVars.pComRangeText; this.mineDetectionTextBox.Text = GlobalVars.pDetRangeText; this.mineAttackTextBox.Text = GlobalVars.pAttRangeText; //触发了TextChanged事件,需要修订OK按钮的失效属性 this.paramsSettingOkButton.Enabled = false; }
视图效果:
项目代码:
http://yunpan.cn/Q9AmY6HbSBzaI
注:下节会修订坐标轴,添加原点及标识,添加坐标轴箭头及表示,坐标轴虚线化。
相关文章推荐
- C#Windows窗体界面设计_攻击决策项目_03_数据绘图_02_修订坐标轴和ParamsForm文本框数据
- C#Windows窗体界面设计_攻击决策项目_03_数据绘图_03_绘制雷点
- C#Windows窗体界面设计_攻击决策项目_01_系统架构
- C#Windows窗体界面设计_攻击决策项目_02_设计窗体_01_主窗体
- C#Windows窗体界面设计_攻击决策项目_02_设计窗体_04_修订主窗体工具栏和状态栏
- C#Windows窗体界面设计_攻击决策项目_02_设计窗体_03_设置窗体弹出退出顺序
- C#Windows窗体界面设计_攻击决策项目_真实轨迹RealTrack
- C#Windows窗体界面设计_01_绘制三角函数_五点作图法
- C#Windows窗体界面设计_01_绘制三角函数_附强制类型转换
- C#Windows窗体界面设计_01_绘制三角函数_五点作图法
- C#Windows窗体界面设计_攻击决策项目_02_设计窗体_02_子窗体
- C#Windows窗体界面设计_03_坐标系平移 旋转 镜像
- C#Windows窗体界面设计_02_绘制三角函数_多点作图法
- C#Windows窗体界面设计_04_添加PictureBox控件绘图
- C#Windows窗体界面设计_06_通过调整坐标系来调整数据
- C#Windows窗体界面设计_05_添加菜单栏 工具栏 状态栏 按钮
- C#Windows窗体界面设计_07_多窗体设计
- C#Windows 窗体设计-实现欢迎界面-显示About窗体-在托盘中写入应用程序图标
- c# WindowForm练习项目主窗体设计
- C#Windows窗体界面设计_01_绘制三角函数_附强制类型转换