Delphi中实现事件“注入”(转)

原文地址:https://blog.csdn.net/zhmnsw/article/details/1490587

C#中,事件是以委托的形式出现的,我们可以使用+=操作符来实现一个组件中同一事件的串联。但是,在Delphi中,事件是以procedure of Object的形式出现的,没有+=操作符的支持,也就是说,一个组件的事件只能指向一个函数地址(C#中的委托使用了指针列表来保存委托,因此可以实现多个事件的挂接)。那么,有没有一个变通的方法来间接实现事件的随意“注入”(即不影响原有事件,把自己的多个事件插入到事件执行队列,或者一次插入到多个事件中)呢?答案是肯定的。好,让我们一起来。

所谓事件,实质是一个实现定义了形式的函数指针,那么既然是指针,就可以用地址来表示。

比如,有一个按钮,我们想在它的OnClick事件注入我们的代码,那么可以这样:

//这里是全局变量
var
  temp: TNotifyEvent;


//下面是实现
begin
  temp := Button.OnClick; //把原有事件保留到临时的变量
  Button.OnClick := myClick; //用我们的事件替换之
end;

//在myClick事件函数中写入
if Assigned(temp) then
  temp(Sender);

这样,我们成功的使用自己的事件“注入”了原有事件。

这是在组件或者事件个数明确的情况下实现的,那么组件的个数不明确的话我们该怎么办呢?其实,我们完全可以使用指针数组/列表来实现事件的“注入”,只是其中使用了一个小小的转换来保证类型的一致。

比如,有一个PageControl控件,我们需要注入到每一个TabSheet的OnShow中,而对于TabSheet的个数我们不明确,那么可以这样:

//定义两个列表
var
    OnTabSheetShowCodeList: TList;  //用于保存TMethod.Code的内容
    OnTabSheetShowDataList: TList;  //用于保存TMethod.Data的内容

//在注入代码实现中
var
  os: TMethod;
begin
  for i := 0 to PageControl.PageCount -1 do
  begin
    os := TMethod(PageControl.Pages[i].OnShow); //获取指定TabSheet的OnShow事件,并将其转换成TMethod类型,这里是关键
    OnTabSheetShowCodeList.Add(os.Code); //保存该函数指针的地址
    OnTabSheetShowDataList.Add(os.Data); //保存该函数指针的额外数据
    PageControl.Pages[i].OnShow := myOnShow; //使用我们自己的事件函数来替换之
  end;
end;

//那么在myOnShow中
var
  onShow: TNotifyEvent;
begin
  if (Sender <>nil) and(Assigned((Sender as TTabSheet).PageControl)) then
  begin
    TMethod(onShow).Code := (FOnTabSheetShowCodeList.Items[(Sender as TTabSheet).pageIndex]); //恢复函数指针的地址
    TMethod(onShow).Data := (FOnTabSheetShowDataList.Items[(Sender as TTabSheet).pageIndex]); //恢复函数指针的额外数据
    if (Assigned(onShow)) then
    begin
      onShow(Sender); //调用原始事件
    end;
  end;
end;

上面代码最不容易理解的是 TMethod(onShow).Data 这个变量,网上很多例子都对它赋予了 Self,但是在本例中,赋予Self反而会在调用原始事件时出错,原因很简单,TMethod.Data 是对象实例 (Instance) 的首地址,TMethod 的结构定义方式就是目前 O-O 语言实现的原理。Code 和 Data 分离,Code 表示类的首地址,Data 表示类的实例的首地址。方法表示对 Code 的偏移量,字段 (Field) 表示对 Data 的偏移量。因此,如果赋予其 Self 的话,在调用原始事件时就会出现原始调用者指针丢失,造成内存访问异常。

posted @ 2024-11-04 06:53  汉学  阅读(28)  评论(0)    收藏  举报