第二节:在线程时空中操作界面(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 是个特殊的存在,它可以在线程时空里,把代码塞到主线程时空里去运行。
 
第三节,将实现线程如何保持生命力,创建后可以反复使用。慢慢进入实用阶段了,请不要错过。
 
 
 

delphi 线程教学第二节:在线程时空中操作界面(UI)的更多相关文章

  1. delphi 线程教学第一节:初识多线程

    第一节:初识多线程   1.为什么要学习多线程编程?   多线程(多个线程同时运行)编程,亦可称之为异步编程. 有了多线程,主界面才不会因为耗时代码而造成“假死“状态. 有了多线程,才能使多个任务同时 ...

  2. VC在线程中操作界面

    http://blog.csdn.net/tingsking18/article/details/4399199 多线程是我们在编程中经常遇到的问题,线程执行完后往往要把执行的结果传给主线程,但是MF ...

  3. delphi 线程教学第一节:初识多线程(讲的比较浅显),还有三个例子

    http://www.cnblogs.com/lackey/p/6297115.html 几个例子: http://www.cnblogs.com/lackey/p/5371544.html

  4. android kotlin 子线程中调用界面UI组件崩溃

    UI 只能在主线程内更新,子线程需要更新UI组件时可以这样: fun fuck(){ Executors.newSingleThreadExecutor().execute{ // url reque ...

  5. delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行

    第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行     以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...

  6. delphi 线程教学第四节:多线程类的改进

    第四节:多线程类的改进   1.需要改进的地方   a) 让线程类结束时不自动释放,以便符合 delphi 的用法.即 FreeOnTerminate:=false; b) 改造 Create 的参数 ...

  7. delphi 线程教学第三节:设计一个有生命力的工作线程

    第三节:设计一个有生命力的工作线程   创建一个线程,用完即扔.相信很多初学者都曾这样使用过. 频繁创建释放线程,会浪费大量资源的,不科学.   1.如何让多线程能多次被复用?   关键是不让代码退出 ...

  8. Netty源码分析第2章(NioEventLoop)---->第3节: 初始化线程选择器

    Netty源码分析第二章:NioEventLoop   第三节:初始化线程选择器 回到上一小节的MultithreadEventExecutorGroup类的构造方法: protected Multi ...

  9. Netty源码分析第2章(NioEventLoop)---->第4节: NioEventLoop线程的启动

    Netty源码分析第二章: NioEventLoop   第四节: NioEventLoop线程的启动 之前的小节我们学习了NioEventLoop的创建以及线程分配器的初始化, 那么NioEvent ...

随机推荐

  1. linux 中 开放端口,以及防火墙的相关命令

    最近公司需要在 生产环境上线系统,碰到一些防火墙以及开放端口的问题,在此来 复习mark下   1.设定   [root@localhost ~]# /sbin/iptables -I INPUT - ...

  2. print函数详解及python打印99乘法表的不同方法

    首先你需要了解print的原型,并且要知道在python2和python3中print函数功能不同,不只是表现在后面带不带()一方面! 在python3中,通过help(print)可以得到print ...

  3. python基础18 ---多态与绑定方法

    一.抽象类 1.抽象类的定义:从一堆类中抽象出相同的内容,重新组成一个新的类,这样的类属于抽象类. 2.香蕉类是一类水果,苹果类是一类水果,葡萄类是一类水果,但是他们都属于水果,从他们这些类中可以抽象 ...

  4. C#调用大漠插件

    大漠插件是一个很不错的东西,在按键精灵和易语言里面用得很多,可以后台找图找字,写游戏自动脚本用得特别多.前面写一个微信的自动脚本,查了一些资料,易语言不太熟悉,按键精灵功能上可能不好实现,就找了些资料 ...

  5. python 时间感觉能用到的

    datetime, string, timestamp 互转 import time import datetime print datetime.datetime.now() print datet ...

  6. 【leetcode】Balanced Binary Tree

    Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary ...

  7. RabbitMQ之Exchange Direct模式

    场景: 生产者发送消息到交换机并指定一个路由key, 消费者队列绑定到交换机时要指定路由key(key匹配就能接受消息,key不匹配就不能接受消息) 例如:我们可以把路由key设置为insert ,那 ...

  8. Linux课程---3、Linux远程登录和传输(操作Linux服务器软件)

    Linux课程---3.Linux远程登录和传输(操作Linux服务器软件) 一.总结 一句话总结: xshell:Xshell是一个强大的安全终端模拟软件 Xshell是一个强大的安全终端模拟软件, ...

  9. maven 3.2.5 的安装及简单示例

    http://www.mvnrepository.com 一直没有使用maven,它的作用就不说了,这二天需要用到,发现网上都是以前的版本,所以,我一边配置,一边记录. 一 下载maven 现在很多I ...

  10. C++(七)— 进程、线程及区别

    1.进程(process) 狭义定义:进程就是一段程序的执行过程. 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,在传统的操作系统中,进程既 ...