delphi 线程教学第二节:在线程时空中操作界面(UI)

第二节:在线程时空中操作界面(UI)
 
1.为什么要用 TThread ?
 
TThread 基于操作系统的线程函数封装, 隐藏了诸多繁琐的细节。
适合于大部分情况多线程任务的实现。这个理由足够了吧?
什么?你要用 windows 的线程 api 来实现多线程?
我可以负责任地告诉你,如果你用 api 来实现多线程任务,
加之你天资聪明,对 delphi 的面向对象思想掌握得非常快,
那么最终也你也会写一个与 TThread 类似的东西来提高开发效率。
何必折腾呢? 要相信 delphi 的工程师,人家早已看透了一切。咳咳。
同理,要相信微软的工程师,windows 操作系统是没有啥大问题的。
更同理,要相信设计手机的工程师,不需要贴膜,人家好不容易把才手机变薄的。
哈哈,扯远了。。。
(本教程默认操作系统为 windows 7/10 , delphi 的版本为 XE8,大多数代码均能在 XE2 上运行)
 
2.线程时空中操作界面(UI)到底有什么门道?
 
很多教程中都一再强调,线程时空里,不准直接去更新 UI ,但似乎没有说明原因。
我们假设UI 界面允许多个线程同时去更新,看看会发生什么情况。
如果两个线程,同时都在界面相同的区域进行画图操作,比如一个要画绿色,一个要红色,
那么最终,界面上是不是可能出现一个大花脸?
可以这样朴实地理解,就知道为什么 UI 不允许多线程去操作了。 不是不能,是不得已。
(线程中不允许直接操作 UI,在安卓下同样适用)
 
3. TThread.Synchronize() 原理。
 
是用 SendMessage 函数,发了一个 WM_NULL 消息给窗口。
窗口接到消息后再去更新界面。窗口消息响应事件可以理解为主线程时空。
 
以下是接上节的实例,来看如何正确地显示计算结果在窗口上。
 
unit  Unit10;
interface
uses
   Winapi . Windows, Winapi . Messages, System . SysUtils, System . Variants, System . Classes,  Graphics,
   Vcl . Controls, Vcl . Forms, Vcl . Dialogs, uAccumulation, Vcl . StdCtrls;
type
   TForm10 =  class (TForm)
     Edit1: TEdit;
     Button1: TButton;
     procedure  Button1Click(Sender: TObject);
   private
     procedure  OnAccumulated(Sender: TAccumulationThread);
   end ;
 
implementation
{ $R  *.dfm}
 
procedure  TForm10 . Button1Click(Sender: TObject);
var
   accThread: TAccumulationThread;
begin
   accThread := TAccumulationThread . Create( true );
   accThread . OnAccumulated := self . OnAccumulated;  //指定事件。
   accThread . FreeOnTerminate :=  true // 线程结束后自动释放
   accThread . Num :=  100 ;
   accThread . Start;
end ;
 
procedure  TForm10 . OnAccumulated(Sender: TAccumulationThread);
begin
   // 这里是线程时空
   // 要更新 UI ,要用 Synchorinize 把更新的操作
   // 塞到主线程时空里去运行。注意理解:“塞!”
   TThread . Synchronize( nil ,
     procedure
     begin
       // 这里的代码被塞到主线程时空里去了。
       Edit1 . Text := inttostr(Sender . Total);
     end );
   // Synchronize 第一个参数是 nil
   // 第二个参数是一个匿名函数 什么是匿名函数? 以后会介绍到。
end ;
end .
 
unit  uAccumulation;
interface
uses
   Classes;
type
   TAccumulationThread =  class //此为提前申明
   TOnAccumulated =  procedure (Sender: TAccumulationThread)  of  object ;
   // 如果不提前申明,Sender 就要定义成 TObject
   // 在事件函数中,要操作 Sender 就需要强制转换
   TAccumulationThread =  class (TThread)
   protected
     procedure  Execute; override;
   public
     Num:  integer ;
     Total:  integer ;
     OnAccumulated: TOnAccumulated;
   end ;
 
implementation
 
procedure  TAccumulationThread . Execute;
var
   i:  integer ;
begin
   Total :=  0 ;
   if  Num >  0  then
   begin
     for  i :=  1  to  Num  do
       Total := Total + i
   end ;
   // 当计算完成后,就调用  OnAccumulated 通知调用者
   if  Assigned(OnAccumulated)  then
     OnAccumulated(self);
end ;
end .
 
 4. 哪些代码运行在线程时空?
 
Execute 函数中运行的、调用的代码,都是”线程代码“。与代码书写位置无关!!!
Sysnchronize 是个特殊的存在,它可以在线程时空里,把代码塞到主线程时空里去运行
 
第三节,将实现线程如何保持生命力,创建后可以反复使用。慢慢进入实用阶段了,请不要错过。
 
 
 

转载于:https://www.cnblogs.com/lackey/p/6296414.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值