一直想弄清楚线程是如何工作的,一直在找相关的实例都没有找到,没有找到容易看懂的实例。今天终于找到一个,觉得很简单,把它转到这里来分享一下。
要实现的效果是:
点击按纽,窗口上的label上出现1~100数字的变化。
窗口上有两个控键,一个label,一个button。
第一个实例(把窗口上的label上文字改成100):
using System;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "100";
}
}
}
这个是最简单的实例,应该不难看懂。
第二个实例(点击button,循环显示0动态变化到100数字):
using System;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "0";
}
private void button1_Click(object sender, EventArgs e)
{
for(int i=0;i<101;i++)
{
label1.Text = i.ToString();
}
}
}
}
private void run()
{
for(int i=0;i<101;i++)
{
label1.Text = i.ToString();
}
}
using System;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "0";
}
private void button1_Click(object sender, EventArgs e)
{
run(); //调用run函数
}
private void run()
{
for(int i=0;i<101;i++)
{
label1.Text = i.ToString();
}
}
}
}
using System;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
int i; //全局变量i
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "0";
}
private void button1_Click(object sender, EventArgs e)
{
run();
}
private void run()
{
i = 0;
timer1.Interval = 1000; //设置timer1的间隔时间
timer1.Start(); //启动timer1
}
private void timer1_Tick(object sender, EventArgs e) //timer1的Tick事件
{
i++;
if (i > 100)
{
timer1.Stop();
}
label1.Text = i.ToString();
}
}
}
同样的,我们运行一下,看看结果,很好,我们能够看到0~100循环的过程了。
以上是我们平常的做法,让label动态变化的效果,下面我们开始使用线程来实现上面的功能。
创建线程就算完成了,那么怎么运行线程呢?
其实和启动timer1是类似的,thread1.Start();就运行了我们创建的线程thread1。
好了,大功告成!哈哈,别着急,既然我们创建了线程,那么在关闭窗口的时候,就要撤消线程。
添加FormClosing事件,在事件内部写如撤消线程的代码:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (thread1.IsAlive) //判断thread1是否存在,不能撤消一个不存在的线程,否则会引发异常
{
thread1.Abort(); //撤消thread1
}
}
这样才算大功告成嘛,整理的代码如下:(在第三个实例的基础上加以改动)
第五个实例
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
private Thread thread1;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "0";
}
private void button1_Click(object sender, EventArgs e)
{
thread1 = new Thread(new ThreadStart(run));
thread1.Start();
}
private void run()
{
for (int i = 0; i < 101; i++)
{
label1.Text = i.ToString();
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (thread1.IsAlive)
{
thread1.Abort();
}
}
}
}
运行看看,按button1,出错了,怎么回事呢????
哈哈~~看看出错原因,是在run函数内的label1.Text = i.ToString();语句上出的错,没错啊,语法正确啊
哈哈~~我来解释一下,出错的原因是为了保护数据的安全所以不能跨线程调用控件,而label1.Text = i.ToString();句则是在线程thread1上面调用主线程的控件,肯定会出错的!!
怎么办呢?用委托啊(有关委托,请参考其它资料,我就不多说了)
我的理解就是,线程thread1不能调用主线程的lable1,所以,就委托主线程来改变lable1的值。
首先看一个例子:(从例3改写)(并不创建线程,仅有主线程)
创建一个函数,用来设置lable1的值;
private void set_lableText(string s)
{
label1.Text = s;
}
当需要改变lable1的值时,就调用它,并传递要改变的值。
第六个实例:
using System;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "0";
}
private void button1_Click(object sender, EventArgs e)
{
run(); //调用run函数
}
private void run()
{
for(int i=0;i<101;i++)
{
set_lableText( i.ToString() );
}
}
private void set_lableText(string s)
{
label1.Text = s;
}
}
}
首先声明一个委托:
delegate void set_Text(string s);
创建一个全局委托变量:(应该是变量吧)
set_Text Set_Text; //请注意大小写,set_Text是委托类型,Set_Text是创建的委托(当然,这里的命名是随意的)
类似于创建线程,需要进行实例化:
Set_Text = new set_Text(set_lableText); //括号内的set_lableText是委托要调用的函数(也就是例6写的set_lableText(string s);函数)
现在,就剩下调用委托了,怎么调用委托呢?很简单。
同过Invoke来调用,语句如下:
label1.Invoke(Set_Text, new object[] { i.ToString() });
//Set_Text是调用的委托,object[]则是我们要传递的参数
整理代码如下:(例7)
第七个实例:使用多线程实现0~100动态变化效果
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
private Thread thread1; //定义线程
delegate void set_Text(string s); //定义委托
set_Text Set_Text; //定义委托
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "0";
Set_Text = new set_Text(set_lableText); //实例化
}
private void button1_Click(object sender, EventArgs e)
{
thread1 = new Thread(new ThreadStart(run));
thread1.Start();
}
private void set_lableText(string s) //主线程调用的函数
{
label1.Text = s;
}
private void run()
{
for (int i = 0; i < 101; i++)
{
label1.Invoke(Set_Text, new object[] { i.ToString() }); //通过调用委托,来改变lable1的值
Thread.Sleep(1000); //线程休眠时间,单位是ms
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (thread1.IsAlive) //判断thread1是否存在,不能撤消一个不存在的线程,否则会引发异常
{
thread1.Abort(); //撤消thread1
}
}
}
}