该项目是一个很小的项目,目的是为了了解多线程。其最后实现的界面如下:
当点击开始按钮时,则上面6个lable标签都会随机取数,按下结束按钮,则会停止。
思路:1.设计界面-> 2.实现按钮的功能 过程:一步一步探索
步骤:1.首先从工具栏中拖入两个按钮,分别进行命名,如上图;
2.转到按钮界面,编写代码实现6个lable标签的显示:
public Form1()
{
InitializeComponent();
InitLables();
}
private void InitLables()
{
for (int i = 0; i < 6; i++)
{
Label lable = new Label();
lable.Visible = true;//lable的可见性
lable.AutoSize = true; //lable自动更换大小
lable.Location = new Point(50 + 65 * i, 120); //设置lable的位置(注意此时位置如何设置,使用new Point()方法,其中方法内的坐标定义的技巧,也需要熟练掌握)
lable.Text = "0";//初始化为0,可根据其判断位置是否美观
this.Controls.Add(lable);//不可缺少,Controls获取包含在控件内的 控件的集合
}
}
3.点击开始按钮后,触发的事件:
思路:应该事先6个标签按钮的随机取数,必定会用到循环语句;则编写代码如下:
public partial class Form1 : Form
{
public List<Label> lables = new List<Label>();
}
private void InitLables()
{
for (int i = 0; i < 6; i++)
{
Label lable = new Label();
lable.Visible = true;
lable.AutoSize = true;
lable.Location = new Point(50 + 65 * i, 120);
lable.Text = "0";
lables.Add(lable);
this.Controls.Add(lable);
}
}
private void btnStart_Click(object sender, EventArgs e)
{
Random r = new Random();
while (true)
{
foreach (var lable in lables)
{
lable.Text = r.Next(1, 100).ToString();
}
}
}
完成该步骤之后,运行 并没有得到想要的结果,调试之后,发现其进图了死循环,只是主线程在此切断。故添加线程如下:
private void btnStart_Click(object sender, EventArgs e)
{
Thread thread = new Thread(delThread);
thread.IsBackground=true;
thread.Start();
}
public void delThread()
{
Random r = new Random();
while (true)
{
foreach (var lable in lables)
{
lable.Text = r.Next(1, 100).ToString();
}
}
}
此时运行后,出现如下错误:线程间操作无效: 从不是创建控件“”的线程访问它。
故编写代码如下:
public Form1()
{
InitializeComponent();
InitLables();
Control.CheckForIllegalCrossThreadCalls = false;
}
4.最后实现取消按钮的触发事件:
public partial class Form1 : Form
{
public List<Label> lables = new List<Label>();
public bool IsStop{get;set;}
public Form1()
{
InitializeComponent();
InitLables();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void InitLables()
{
for (int i = 0; i < 6; i++)
{
Label lable = new Label();
lable.Visible = true;
lable.AutoSize = true;
lable.Location = new Point(50 + 65 * i, 120);
lable.Text = "0";
lables.Add(lable);
this.Controls.Add(lable);
IsStop = false;
}
}
private void btnStart_Click(object sender, EventArgs e)
{
Thread thread = new Thread(delThread);
thread.IsBackground=true;
IsStop = false;
thread.Start();
}
public void delThread()
{
Random r = new Random();
while (!IsStop)
{
foreach (var lable in lables)
{
lable.Text = r.Next(1, 100).ToString();
}
Thread.Sleep(180);//让随机数出现的速度变慢
}
}
private void btnEnd_Click(object sender, EventArgs e)
{
IsStop = true;
}
}
这样就完成了!!!
但是 Control.CheckForIllegalCrossThreadCalls = false;只是权宜之计,我们应该向办法将其更改掉:
public List<Label> lables = new List<Label>();
public bool IsStop{get;set;}
public Form1()
{
InitializeComponent();
InitLables();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void InitLables()
{
for (int i = 0; i < 6; i++)
{
Label lable = new Label();
lable.Visible = true;
lable.AutoSize = true;
lable.Location = new Point(50 + 65 * i, 120);
lable.Text = "0";
lables.Add(lable);
this.Controls.Add(lable);
IsStop = false;
}
}
private void btnStart_Click(object sender, EventArgs e)
{
Thread thread = new Thread(delThread);
thread.IsBackground=true;
IsStop = false;
thread.Start();
}
public void delThread()
{
Random r = new Random();
while (!IsStop)
{
foreach (var lable in lables)
{
//线程间操作无效: 从不是创建控件“”的线程访问它。
//说明:WinFrom里面的控件只能被创建他的线程访问。跨线程访问会抛出异常。
if (lable.InvokeRequired)//InvokeRequired为true,代表跨线程访问 (当前线程调用了另一个线程的控件)。
{
//Invoke:Msdn,会沿着lable标签去找 Form窗体 找到创建Form窗体的那个线程 执行下面的方法
lable.Invoke(new Action<string, Label>(SetText), r.Next(0, 10).ToString(), lable);
// label.Invoke(SayHello);
//SetText(r.Next(0,10).ToString(),label);
}
else
{
lable.Text = r.Next(1, 31).ToString();
}
}
Thread.Sleep(180);
}
}
public void SetText(string txt, Label lb)
{
lb.Text = txt;
}
private void btnEnd_Click(object sender, EventArgs e)
{
IsStop = true;
}