在Win32 Delphi 模拟多播事件

原文地址:http://delphi.about.com/library/weekly/aa051005a.htm

    

   在Win32 Delphi OOP中,通常一个组件的事件句柄只能关联一个方法。而在Delphi的.Net版本,多个事件处理代码能够被绑定到一个相同的事件上面。这篇文件将为你介绍一个在Win32 Delphi 模拟多播事件的方法。

-----------------------------------------------------------------------------------------------------------------------------

当你用Delphi开发应用(32位)程序的时候,你总是要写一些代码去处理组件的事件。比如说,你拖一个按钮在一个窗体上,然后双击这个按钮,一个空的事件句柄将被创建,也就是你将要写代码接收用户单击动作的地方。

Win32 Delphi仅仅允许你用一个方法作为一个组件的某个事件的处理代码。

Delphi的.Net版本开始引入多播事件的概念。开发人员能够关联两个或者多个方法到某个事件,而且在事件触发的时候可以被全部的调用。

让我看下如何构建一个Win32 Delphi对象来维持一个它的事件方法列表-由此来模拟多播事件的处理。

在开始之前,我强烈建议你再次熟悉下有的Delphi OOP自定义组件开发的印象。

Win32 Delphi 一个简单的多播事件处理的例子

首先,我们将定义一个简单类(TMultiEventClass)和唯一的一个TMutliEvent事件类型。我们将用一个fMultiEventHandlers TList对象来存储一个在事件触发时将被调用的所有方法的列表。这个 Delphi的TList类被设计用来作为一种数组方式存储机制对于指针类型数据。

在设计中,Delphi的每个方法(函数或者过程)都可以用一个TMethod类型来代表。比如说,一个TMethod类型能够用来执行一个方法仅仅通过它的名字

type
  PMethod = ^TMethod;
  TMutliEvent = procedure(const Value : string) of object;
  TMultiEventClass = class
  private
    fMultiEventHandlers : TList;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AddMultiEvent(const Value: TMutliEvent);
    procedure RemoveMultiEvent(const Value: TMutliEvent);
    procedure FireMultiEvent;
  end;

上面的代码是TMultiEventClass类的定义部分。fMultiEventHandlers作为一个私有列表用来存储将要处理的TMutliEvent事件类型方法指针。由于这个类允许多个事件指针连接到一个事件上面 ,所以我们需要两个相关的过程来增加或者移除事件句柄:AddMultiEvent 和 RemoveMultiEvent。

下面的代码是实现部分:

{ TMultiEventClass }
//create the event handlers storage
constructor TMultiEventClass.Create;
begin
  inherited Create;
  fMultiEventHandlers := TList.Create;
end;
//clean up
destructor TMultiEventClass.Destroy;
var
  cnt: Integer;
begin
  for cnt := 0 to -1 + fMultiEventHandlers.Count do
    Dispose(fMultiEventHandlers[cnt]);
  fMultiEventHandlers.Free;
  inherited;
end;
//add an event handler to the list
procedure TMultiEventClass.AddMultiEvent(
  const Value: TMutliEvent);
var
  h: PMethod;
begin
  h := New(PMethod);
  h^.Code := TMethod(Value).Code;
  h^.Data := TMethod(Value).Data;
  fMultiEventHandlers.Add(h);
end;
//remove an event handler from the list (if there)
procedure TMultiEventClass.RemoveMultiEvent(
  const Value: TMutliEvent);
var
  cnt: Integer;
begin
  for cnt := 0 to -1 + fMultiEventHandlers.Count  do
  begin
    if (TMethod(Value).Code = 
        TMethod(fMultiEventHandlers[cnt]^).Code) and
       (TMethod(Value).Data = 
        TMethod(fMultiEventHandlers[cnt]^).Data) then
    begins
      Dispose(fMultiEventHandlers[cnt]);
      fMultiEventHandlers.Delete(cnt);
      Break;
    end;
  end;
end;
//"fire" event (call all handlers)
procedure TMultiEventClass.FireMultiEvent;
var
  cnt: Integer;
  msg : string;
begin
  for cnt := 0 to -1 + fMultiEventHandlers.Count do
  begin
    msg := Format('%d/%d %s',
                  [1 + cnt, 
                   fMultiEventHandlers.Count, 
                   'fired!']);
    TMutliEvent(fMultiEventHandlers[cnt]^)(msg);
  end;
end;

在上面的代码中,FireMultiEvent过程是被用来模仿产生一个事件。在正常的情况下这应该是TMultiEventClass类的一个私有方法,被初始化在其内部。

为了更好的理解上面的代码,我们将用一个简答的Demo来说明问题。拖一个按钮到窗体上,并且放接下来的代码到OnClick事件中:

{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
  test : TMultiEventClass;
begin
  test := TMultiEventClass.Create;
  try
    test.AddMultiEvent(Handler1);
    test.AddMultiEvent(Handler2);
    test.RemoveMultiEvent(Handler1);
    test.AddMultiEvent(Handler3);
    test.FireMultiEvent;
  finally
    test.Free;
  end;
end;

建立一个test对象,首先,用AddMultiEvent方法增加对Handler1和Handler2的引用,然后用RemoveMultiEvnet过程移除对于Handler1的引用,然后Handler3被增加到事件句柄列表中,最后FireMultiEvent过程被执行。

这三个方法的定义是这样的:

procedure TForm1.Handler1(const value: string);
begin
  ShowMessage('h1: ' + value);
end;
procedure TForm1.Handler2(const value: string);
begin
  ShowMessage('h2: ' + value);
end;
procedure TForm1.Handler3(const value: string);
begin
  ShowMessage('h3: ' + value);
end;

当运行程序的时候什么将会发生呢?那个方法将被FireMultiEvent调用?答案是“Handler2"和”Handler2"。

OK,就这样。在Win32 Delphi中的多播事件!如果你不相信我的话,你可以自行下载上面的演示代码并执行下。有问题或者什么想说的?我想你已经知道的:Delphi程序论坛

注:相关搜索“在(Win32)Delphi 模拟类属性”?

posted on 2010-12-16 13:15  JonyOang  阅读(339)  评论(0)    收藏  举报

导航