Delphi:如何动态分配事件处理程序而不覆盖现有的事件处理程序?

12

我需要循环遍历组件并为其分配事件处理程序(例如为所有TButton动态分配OnClick事件)。

ShowMessage('You clicked on ' + (Sender as TButton).Name);
问题在于有些情况下我已经分配了TButton的OnClick事件。 有没有办法解决这个问题? 假设我有一个按钮Button1,它的硬编码OnClick事件处理程序为:
ShowMessage('This is Button1');
在我的“解析”之后,我希望Button1的完整事件处理程序变为:
ShowMessage('This is Button1'); // design time event handler code
ShowMessage('You clicked on ' + (Sender as TButton).Name); // runtime added
注意:我正在寻找一种解决方案,可以让我直接使用TButton而不必从中继承。

类似的问题(包含完整代码的答案):https://dev59.com/yUzSa4cB1Zd3GeqPno5p - mjn
查看TApplicationEvents源代码,你会找到你想要的相同事件接收器。 - Free Consulting
3
您想要的一般术语是“多播事件”,但Delphi没有该功能。 - Rob Kennedy
3个回答

17

你可以在覆盖 OnClick 事件之前查找其赋值,将其保留并在新的事件处理程序中使用它 - 基本上是将事件链接在一起。

像这样:

  var original : TNotifyEvent;

  original := Component.OnClick;
  Component.OnClick := NewMethod;

然后在你的NewMethod中:

  if assigned(original) then original(Sender);

你可能不想使用单个原始变量,而是要使用一个以组件为键的集合。


谢谢你的想法,应该可以行得通。另外,集合的想法(例如泛型TDictionary)非常好。 - UnDiUdin

2

如果你正在编写自己的替换处理程序,可以按照以下步骤进行:

  • 在分配新处理程序之前,将对象的引用和原始处理程序的引用存储在列表或其他结构中。

  • 在您的替换处理程序中,包含代码以检查列表,看看当前对象是否有条目。如果有,调用存储的方法,然后再执行自己的工作。

这相当轻量级(每个条目都是两个指针的列表)。通过一些额外的工作(以支持排序),您甚至可以链接多个替换处理程序。


1

你不能直接这样做,因为Delphi不支持链式事件(我假设是VCL Delphi)。

所以任何需要直接分配OnClick事件的操作都不会起作用。你可以创建一个拦截器组件,也就是具有以下签名的组件:

type
   TButton = class(stdctrls.TButton)

你需要覆盖OnClick属性,使得写入事件将事件处理程序存储到内部列表中,以便类可以访问。

property OnClick: TNotifyEvent read GetOnClick write SetOnClick;

然后在SetOnClick处理程序中,您将能够将事件处理程序存储在内部列表中。

现在,您必须重写Click过程以便依次调用每个委托(每个事件处理程序)。

procedure Click; override;

这就可以了。

请注意,最终你会有点像子类化TButton类,即使你使用相同的名称... 不管怎样,这是我能想到的最好的解决方案。这个酷炫的事情是,你仍然可以使用赋值而不必知道链式事件,你只需要这样做:

MyButton.OnClick := MyHandler

它将自动链接到其它事件处理程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接