当程序需要做耗时操作,例如访问数据库获取较多的数据、获取大文件MD5、网络访问数据量比较大、界面需要频繁刷新等等,都可以用线程来解决界面卡顿的问题,从而优化用户体验。

在知道TIdThreadComponent之前,建立线程一般都使用继承TThread复写execute过程或者使用createthread。继承TThread写的代码要多一点,createthread又不方便控制线程,于是就有了TIdThreadComponent,集两者的优点,只要拖个控件,线程就出来了。

TIdThreadComponent用的是观察者模式(就是回调),提供以下几个事件回调:

    OnAfterExecute;  //线程Execute过程执行完成
    OnAfterRun; //线程循环执行体完成(不明白的下面看了原理就能明白)
    OnBeforeExecute;//线程Execute过程执行之前
    OnBeforeRun;//线程循环执行体之前(不明白的下面看了原理就能明白)
    OnCleanup;
    OnException;
    OnRun;//执行体
    OnStopped;
    OnTerminate;

原理如下,下图是为了方便理解使用,忽略了一些不常用的细节,例如OnStopped;OnCleanup;事件的回调时机,有兴趣的可以查看控件源码,熟悉线程的同学应该都能看懂并理解源码。

onRun会被重复执行,直到调用控件的stop过程或Terminate过程;

before前缀的回调事件多用于初始化工作,一般建议使用beforeExecute;

after前缀的回调事件多用于释放内存操作,一般建议使用afterExecute;

控件提供stop函数和Terminate函数,进行对线程的停止操作,届时会触发并回调onstop、onTerminate事件,需要结束线程时,建议使用stop函数或active:=false;

 

控件的使用

前提需要安装indy系列,我用的是indy9(我尝试过在Delphi2010上使用indy10,beforeRun和afterRun的触发时机有点不一样)

1.把TIdThreadComponent控件拖到窗体上

2.根据业务需求,在相应的回调事件中写业务处理代码

3.TIdThreadComponent.active := true 开始执行

4.执行效果

 

 在onRun中模拟耗时操作,在onRun执行耗时操作时,界面没有被卡死,依然可以流畅拖动,做其它事情

 

onRun事件处理代码

 

beforeExecute、afterExecute执行的代码:

 

start按钮和stop按钮执行的代码

 

 

 这样,一个线程操作就完成了,非常的方便。

TIdThreadComponent还提供了设置线程优先级,这些就不做介绍了。

 

注意:

在线程里直接操作界面控件是一件危险的事情,有时候控件被销毁了而线程还在运行,此时就会报AV异常,所以在TIdThreadComponent回调事件中有使用到控件的,必须添加控件是否为空判断,例如我代码里写到的

否则,在TIdThreadComponent线程运行期间,关闭窗体会造成异常。

当然你可以使用消息来处理,但消息参数handle要用变量保存,否则也会报错。

 

注意2:

如果TIdThreadComponent没有开启(即没有active:=true或start),直接TIdThreadComponent.Terminate会出异常,而TIdThreadComponent.stop不会

 

posted on 2017-08-31 10:46  King Kwong  阅读(2012)  评论(0编辑  收藏  举报