Delphi 7事件的多处理机制

Delphi程序设计之--经验技巧 这些日子太忙了,今天把剩下的部分贴完,希望对大家有用。看过前一篇的都知道此文的作者和出处,我就不详细说了。{ No. 16 }//对于记录类型Record的分析。实例:type TBaseRec = record   rStr: Integer;   rStr2: String;   rStr3: String; end; TStrRec = record   rStr: Integer;  阅读详情


 Delphi 7事件的多处理机制
Allen Tao
2007-08-19

 

  首先解释一下这个题目。在我使用Delphi 7的过程中发现,一个对象的事件只能被一个过程处理。如果多次给这个对象的事件赋给处理事件的过程,最后真正处理事件的将是最后赋值的那个过程。例如,有类TMyClass中定义了一个事件OnSomeFired,在类TClientClass中该类被实例化,它的事件被处理。如下所示:
constructor TClientClass.Create;
var
  myObj: TMyClass;
begin
  //…
  myObj:= TMyClass.Create;
  myObj.OnSomeFired:= SomeFired1;
  myObj.OnSomeFired:= SomeFired2;
  这里的SomeFired1与SomeFired2都是TClientClass中定义的处理过程。其最终的结果是当OnSomeFired事件发生时,只有SomeFired2被调用。
  但在编程的实际中,往往需要一个事件被多个方法所处理。为此,我参考了一些对这个问题的解决办法,总结得出了一个自己的方法,称为事件的多处理机制。

原理
  Delphi 7中的事件本质上是一种过程指针。但事件类型在定义时要比一般过程指针在最后多一个“of object”,如常用的TNotifyEvent的定义是:
TNotifyEvent = procedure(Sender: TObject) of object;
  因此,给一个事件属性赋值,也就是给一个类的过程指针类型的成员变量赋值,当然是最后一次的赋值才有效。要想多次赋值有效就必须有一个数据结构把每次赋值赋给的过程指针变量都记录下来,最合适的数据结构当然是列表TList。但如果在每一个有事件的类中都加一个记录事件赋值的列表对象,自然是不方便的,而且使用这个列表的代码在不同类中也差不多,应该抽取出来形成一个类。这个类就是事件多处理机制的核心内容。

做法
  要记录事件处理过程,就需要将过程指针变量放入列表对象中。但列表对象只能添加指针类型对象(也就是引用类型),而过程指针变量是指类型变量,不能直接添加。这就需要有一个类对过程指针变量进行包装,转化为指针类型对象。于是,先要定义包装类TCallMethod,如下所示:
TCallMethod = class
  private
    _callback: TMethod;
  public
    property Callback: TMethod read _callback write _callback;
  end;
  这里的TMethod是Delphi预定义的记录类型,任何过程指针变量都可以强制转化为这种类型。之后,再定义记录处理过程的类,如下所示:
  TEventObject = class
  private
    callList: TList;
    function GetItem(i: Integer): TMethod;
    function GetCount: Integer;
  public
    constructor Create;

    procedure Add(p: TMethod);
    procedure Remove(p: TMethod);

    property Count: Integer read GetCount;
    property Items[i: Integer]: TMethod read GetItem;  default;
  end;
  下面是实现部分:
constructor TEventObject.Create;
begin
  callList:= TList.Create;
end;

procedure TEventObject.Add(p: TMethod);
var
  a: TCallMethod;
begin
  a:= TCallMethod.Create;
  a.Callback:= p;
  callList.Add(a);
end;

procedure TEventObject.Remove(p: TMethod);
var
  i: Integer;
begin
  for i:= 0 to GetCount - 1 do
    if (TCallMethod(callList[i]).Callback.Code = p.Code) and
      (TCallMethod(callList[i]).Callback.Data = p.Data) then
      callList.Delete(i);
end;

function TEventObject.GetCount: Integer;
begin
  Result:= callList.Count;
end;

function TEventObject.GetItem(i: Integer): TMethod;
var
  a: TCallMethod;
begin
  a:= TCallMethod(callList[i]);
  Result:= a.Callback;
end;
  从上面的代码可以看到,TEventObject的目的是包装TList对象,屏蔽了TList类的大多数方法,只对外暴露了2个过程、1个属性与1个索引,分别用于添加、删除处理事件过程、获得过程个数及通过序号检索记录的过程变量。

使用
  使用时,在需要使用事件的类中将事件的类型由过程指针改为TEventObject,即可使该事件拥有多处理的能力。如下面代码所示:
  TMyClass=class
  private
    someFired: TEventObject;
  public
    constructor Create;
    procedure DoSth;
    property OnSomeFired: TEventObject read someFired write someFired; // 多处理事件
  end;
  以下是实现代码:
constructor TMyClass.Create;
begin
  Self.someFired:= TEventObject.Create;
end;

procedure TMyClass.DoSth;
var
  i: Integer;
  method: TNotifyEvent;
begin
  if someFired.Count > 0 then
    for i:= 0  to someFired.Count - 1 do
    begin
      method:= TNotifyEvent(someFired[i]); // 在该类中事件的真正类型是TNotifyEvent,因此在触发事件时先要转成这种类型的过程指针后再进行调用
      method(Self);
    end;
end;
  定义了一个包含多处理事件的类后,再看看这种类如果在其客户类中被调用。如以下代码:
{类TClientClass中}
var
  myObj: TMyClass;
  //…
  myObj:= TMyClass.Create;
  myObj.OnSomeFired.Add(SomeFired1);
  myObj.OnSomeFired.Add(SomeFired2);
  当客户类代码中调用TMyClass的DoSth方法时,事件将被触发,而2个处理过程SomeFired1与SomeFired2则会依次调用,实现多处理的目的。

再发展一步
  上面的TEventObject类可以实现事件多处理的目的,但它对加入其中的过程指针类型没有检查,这是一个隐患。因此可以针对每一种事件要求的过程指针类型从TEventObject继承一个类,实现类型检查。如要求事件的类型是TNotifyEvent,就可以继承一个TNotifyEventObject类,如下面代码:
  TNotifyEventObject = class(TEventObject)
  public
    procedure Add(p: TNotifyEvent); overload;
    procedure Remove(p: TNotifyEvent); overload;
  end;
  以下是实现部分:
procedure TNotifyEventObject.Add(p: TNotifyEvent);
begin
  inherited Add(TMethod(p));
end;

procedure TNotifyEventObject.Remove(p: TNotifyEvent);
begin
  inherited Remove(TMethod(p));
end;
  在这个类中重载了添加与移除方法,可以有效地对过程指针类型进行检查。

  以上是我对Delphi 7中事件多处理问题的一个解决办法。如有兴趣,请光临我的博客http://allentao430.spaces.live.com赐教。

实现Windows高性能并发IOCP的DELPHI指南 简介:本文深入探讨了如何利用DELPHI语言实现基于Windows IO Completion Ports(IOCP)的高性能并发应用。IOCP作为Windows操作系统中的一种高效并发I/O技术,通过异步I/O模型显著提高了大量并发请求的处理性能。DELPHI提供的面向对象特性和与Windows API的紧密集成,使得使用IOCP变得更加便捷。 阅读详情

相关推荐

【一步到位】Android Studio 实现安卓连接阿里云物联网云平台

最新版本目前是Android Studio Iguana | 2024.1.2,你可以到官网上去找之前的版本,手上有工作项目的不要去轻易尝试,说不定你就编译失败了,失败了也不要担心,解决就可以了。

m0_73799445的博客 1万+

delphi TMethod

program Test_Method; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TExec = procedure of object; var _func: TMethod; Exec: TExec; procedure Test1; begin Writeln('Hell, word! This is a procedure.'); end; function Test2: Boolean; b.

sonadorje的专栏 1325

openai联合创始人用1000行纯C语言手搓的GPT-2训练代码

不久之前,特斯拉前 AI 总监、OpenAI 联合创始人 Andrej Karpathy 在社交媒体平台 X 上高调宣布,他友好地从 OpenAI 离职,未来将专注于“个人项目”,而后又口口声声说要尝试性地戒掉上网两周,去了 Bhutan(不丹王国)休假。然后就手搓如下代码,我们一起来欣赏.这段代码是一个GPT-2模型的训练实现,包括前向传播、后向传播、参数更新等过程。代码中包含了注释,解释了每个函数和代码块的作用。此外,还有一些辅助函数和结构体,用于数据加载、随机数生成和模型的初始化与释放。这个训练循环还

zhangzhechun的专栏 1209

Delphi中的匿名方法

在js的世界里,基本就是大量的“回调”和“异步”函数,剩下的就是按照顺序执行的javascript代码,所以总的来说,js中无“同步模型”。正是因为如此,javascript在运行时没有“多余的”线程,它们都在同一个“线程”中工作。任何第三方平台,凡是其API-Proxy代理服务器向你“代理转发(重定向)URL”,其响应结果,要么你在浏览器的导航器的地址栏中去取(Navigator.Location),要么你在响应头的redirect参数中去取,它们,都是异步的。Delphi及C++ Builder中,可以

pulledup的博客 1823

Silvaco TCAD仿真4——DeckBuild实战:从示例库到自定义设计

本文详细介绍了Silvaco TCAD仿真工具DeckBuild的实战应用,从示例库的使用到自定义设计的全过程。通过具体案例和参数修改技巧,帮助用户快速掌握TCAD仿真技术,提升半导体器件设计的效率和精度。特别适合需要从基础入门到进阶操作的工程师和研究人员。

weixin_29284657的博客 432

手撕代码系列:Conv2D

在实际的神经网络中,每个卷积核都会对应一个偏置值。这意味着如果网络有多个卷积核,每个卷积核的输出都可以加上对应的偏置。

qq_55794606的博客 908

一个灵巧的Delphi多播实事件现方案.

已转至新博客 http://www.raysoftware.cn/?p=44 一个灵巧的Delphi多播实现方案.必须是支持泛型的Delphi版本.也就是Delphi2009以后.强烈建议用DelphiXE.   用法就是例如写一个Class指定一个Event,触发的时候会通知多个Method.和.NET的多播事件机制是一样的.   用法例如: type   TFakeButto

wr960204(武稀松)的专栏 4098

【乐企】有关乐企能力测试接口对接-基础版(详细)

乐企能力测试接口对接详细代码以及步骤

九七的博客 7655

[转载] Delphi 7事件的多处理机制

  首先解释一下这个题目。在我使用Delphi 7的过程中发现,一个对象的事件只能被一个过程处理。如果多次给这个对象的事件赋给处理事件的过程,最后真正处理事件的将是最后赋值的那个过程。例如,有类TMyClass中定义了一个事件OnSomeFired,在类TClientClass中该类被实例化,它的事件被处理。如下所示:constructor TClientClass.Create;var...

139

本地通知与健康数据的隐私保护方案

随着移动健康(mHealth)应用的普及,本地通知与健康数据的结合为用户提供了更加个性化的健康管理体验。然而,这种便利性也带来了严峻的隐私保护挑战。本文旨在探讨如何在移动应用中实现本地通知功能的同时,确保用户健康数据的隐私安全。本地通知与健康数据结合的技术架构隐私保护的核心技术方案具体算法实现与数学模型实际应用案例分析本文首先介绍背景知识和核心概念,然后深入探讨隐私保护的技术方案,包括算法原理和数学模型。接着提供实际代码实现和应用场景分析,最后讨论未来发展趋势和挑战。

移动开发前沿的博客 1308

【乐鑫】唤醒词修改方法

乐鑫科技的语音识别模块(如ESP-SR)支持自定义唤醒词,但需通过官方工具链完成。

以实战经验介绍行业知识 825

火鸟数据库 linux,firebird数据库

Firebird是一个跨平台的关系数据库系统,该系统使用起来十分方便、安全、可靠,操作和维护起来也是十分简单,且兼容性十分强大,目前能够运行在Windows、linux和各种Unix操作系统上,它既能作为多用户环境下的数据库服务器运行,也提供嵌入式数据库的实现。Firebird是什么?中文名为火鸟数据库是开源数据库,数据安全性比较好,费用也比较低,操作和维护就比较简单。如果需要卸载的话,双击安装程...

weixin_35705011的博客 2393

SolidWorks2020详细步骤安装教程

1、在安装软件前请断开网络连接,需要安装.NETFramework3.5和4.0,最后还要确保把之前安装的旧版本完全卸载,以管理员身份运行SolidWorks_Flexnet_Server\server_remove.bat,然后等到服务“SolidWorksFlexnet服务器”将被删除。12、先不要运行软件,找到_SolidSQUAD_文件夹,将文件夹“ProgramFiles\SOLIDWORKSCorp”中的所有破解文件复制替到“ProgramFiles\SOLIDWORKSCorp”目录下;

qq_53545309的博客 1万+

Firebird介绍

个人认为比较适合做桌面程序数据储存 以下是从网络获取: 1 含义  Firebird特性介绍firebird是一个全功能的,强大高效的,轻量级,免维护的数据库。它很容易让您从单用户,单数据库升级到企业级的应用。   一个firebird数据库服务器能够管理多个独立的数据库,每一个数据库同时可支持多个客户端连结。总之:它是一个开源的,强大在,可以自由使用的数据库(即使是商业上的使用)

生命在于折磨... 1010

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Firebird特性介绍

<br />Firebird特性介绍:firebird是一个全功能的,强大高效的,轻量级,免维护的数据库。它很容易让您从单用户,单数据库升级到企业级的应用。<br /> 一个firebird数据库服务器能够管理多个独立的数据库,每一个数据库同时可支持多个客户端连结。总之:它是一个开源的,强大在,可以自由使用的数据库(即使是商业上的使用)<br /> 关键特性:<br /><br /> [separator]<br /><br /><br /> 支持原子性,并发性,隔离性等概念。<br /> MGA

paluo的专栏 851

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

firebird数据库介绍[转]

firebird数据库介绍 Firebird特性介绍:firebird是一个全功能的,强大高效的,轻量级,免维护的数据库。它很容易让您从单用户,单数据库升级到企业级的应用。 一个firebird数据库服务器能够管理多个独立的数据库,每一个数据库同时可支持多个客户端连结。总之:它是一个开源的,强大在,可以自由使用的数据库(即使是商业上的使用) 关键特性: 支持原子性,并...

deform0032的博客 278

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Firebird 数据库使用心得

公司一个任务,需要一个免安装的嵌入式关系数据库,在试用了对比了 Access 和 Firebird 之后,选择了更简便、性能更好的后者。 Firebird 简介:       firebird是一个真正的关系数据库,支持存储过程、视图、触发器、事务等大型关系数据库的所有特性,它是一个开源的,可以自由使用的数据库(即使是商业上的使用)。具有以下的特点:   支持原子性,并发性

KaedaRukawa的专栏 2069

Firebird学习(01):Firebird数据库简介

概述 Firebird特性介绍:firebird是一个全功能的,强大高效的,轻量级,免维护的数据库。它很容易让您从单用户,单数据库升级到企业级的应用。  一个firebird数据库服务器能够管理多个独立的数据库,每一个数据库同时可支持多个客户端连结。总之:它是一个开源的,强大在,可以自由使用的数据库(即使是商业上的使用) 关键特性: 支持原子性,并发性,隔离性等

阿发的专栏 2596

用了下FIREBIRD,发现真的不错哦

Firebird特性介绍:firebird是一个全功能的,强大高效的,轻量级,免维护的数据库。它很容易让您从单用户,单数据库升级到企业级的应用。 一个firebird数据库服务器能够管理多个独立的数据库,每一个数据库同时可支持多个客户端连结。总之:它是一个开源的,强大在,可以自由使用的数据库(即使是商业上的使用) 关键特性: [separator] 支持原子性,并发性...

weixin_30532759的博客 140

关于Firebird数据库

关键特性:  支持原子性,并发性,隔离性等概念。  MGA:  支持事务的多个版本功能,  存储过程:  使用PSQL(Procedure SQL),你可以创建强大的存储过程来处理服务上的所有数据,你可以使用select Stored Procedure的形式,使用存储过程,以得到一个虚拟的表结构的结果。这样的话,你就可以很容易的在报表中使用它。  事件:  存储过程和

sonnydica的专栏 1055
上一篇: libhaur笔记1:Usage
下一篇: DELPHI 中如何提升进程令牌
iseekcode
博客等级 码龄18年 36粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值