在Delphi 7中停止事件传播

时间:2012-05-08 10:07:54

标签: delphi event-handling mouseevent delphi-7

我在Delphi 7中遇到了关于事件传播的问题(由于我的无知)。

我被要求在表单上的某些控件上动态附加OnMouseUp事件处理程序(我对此事情很好),但如果OnMouseUp存在,则{{不得处理该控件上的事件。

背景

如果你问这背后的原因,那么,我负责修改一个旧的生产监控应用程序(叹气),从现在开始必须适应某些控件的条件行为,直接响应前者单击特殊功能按钮。

其中一些控件已经有一个OnClick事件处理程序;团队提出的第一个解决方案是准时干预每个OnClick处理程序,并管理与特殊功能按钮状态相关的上下文操作。

我建议利用已经存在的面向对象设计应用程序表单:它们都继承自相同的自定义祖先对象,因此我计划在那里插入一个初始化方法来动态附加OnClick个事件在子类中声明支持它的控件。

需要

我在此不要求对所有这些(可能缺乏)设计优点进行验证或质疑(顺便说一下,经过大量的思考和推理,它似乎是我们可以少走的路径痛);我的问题是,要进行此类设计,我必须让动态附加的OnMouseUp事件处理程序停止事件传播到这些控件上预先存在的OnMouseUp事件。

Delphi 7有可能吗?

2 个答案:

答案 0 :(得分:6)

请注意,以下内容未明确回答此问题。这是对概念重新设计的一个提议(重定向OnClick事件而不是添加额外的OnMouseUp)。它是关于如何将OnClick事件处理程序(如果已分配一些)重定向到另一个(常见的)OnClick事件处理程序(可能会被过滤,如果需要)。它还包括将其恢复到原始状态的方法。

在下面的示例中,我将尝试向您展示如何替换然后可选地还原特定的OnClick事件处理程序(如果组件已编写一些)。对已发布OnClick事件的所有组件执行此操作,因此您无需事先知道组件类是否具有可用的OnClick事件(但可以非常简单地将其修改为仅使用特定类)。

代码包括以下内容:

  • OnSpecialClick - 当您调用ReplaceOnClickEvents过程时,它是绑定所有OnClick事件的事件处理程序,请注意 它必须发布为RTTI可见!!!

  • Button1Click - 这里代表应该替换的旧事件处理程序,它在设计时绑定到Button1.OnClick事件

    < / LI>
  • ReplaceOnClickEvents - 方法,它遍历表单上的所有组件并检查当前迭代的组件是否已分配OnClick事件处理程序;如果是这样,它将它存储到备份集合中并通过OnSpecialClick

  • 替换此事件处理程序
  • RestoreOnClickEvents - 方法,可恢复原始的OnClick事件处理程序;它遍历备份集合并将事件方法分配给其存储的组件实例

  • CheckBox1Click - 此复选框单击事件是指在公共模式和特殊模式之间切换(CheckBox1选中状态表示为特殊模式),只有这个OnClick事件不会被ReplaceOnClickEvents调用替换(因为你无法将模式恢复到正常状态)

这就是:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TypInfo, StdCtrls, Contnrs;

type
  TEventBackup = class
    Component: TComponent;
    OnClickMethod: TMethod;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
  private
    procedure ReplaceOnClickEvents;
    procedure RestoreOnClickEvents;
  published
    procedure OnSpecialClick(Sender: TObject);
  end;

var
  Form1: TForm1;
  EventBackupList: TObjectList;

implementation

{$R *.dfm}

procedure TForm1.OnSpecialClick(Sender: TObject);
begin
  ShowMessage('Hi, I''m an OnSpecialClick event message!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Hi, I''m just that boring original OnClick event message!');
end;

procedure TForm1.ReplaceOnClickEvents;
var
  I: Integer;
  Component: TComponent;
  EventMethod: TMethod;
  EventBackup: TEventBackup;
begin
  for I := 0 to ComponentCount - 1 do
  begin
    Component := Components[I];
    if Component = CheckBox1 then
      Continue;

    if IsPublishedProp(Component, 'OnClick') then
    begin
      EventMethod := GetMethodProp(Component, 'OnClick');
      if Assigned(EventMethod.Code) and Assigned(EventMethod.Data) then
      begin
        EventBackup := TEventBackup.Create;
        EventBackup.Component := Component;
        EventBackup.OnClickMethod := EventMethod;
        EventBackupList.Add(EventBackup);
        EventMethod.Code := MethodAddress('OnSpecialClick');
        EventMethod.Data := Pointer(Self);
        SetMethodProp(Component, 'OnClick', EventMethod);
      end;
    end;
  end;
end;

procedure TForm1.RestoreOnClickEvents;
var
  I: Integer;
  EventBackup: TEventBackup;
begin
  for I := 0 to EventBackupList.Count - 1 do
  begin
    EventBackup := TEventBackup(EventBackupList[I]);
    SetMethodProp(EventBackup.Component, 'OnClick', EventBackup.OnClickMethod);
  end;
  EventBackupList.Clear;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    ReplaceOnClickEvents
  else
    RestoreOnClickEvents;
end;

initialization
  EventBackupList := TObjectList.Create;
  EventBackupList.OwnsObjects := True;

finalization
  EventBackupList.Free;

end.

答案 1 :(得分:1)

正如TLama和TOndrej所说,有几种方法可以实现你的目标:

  1. if Assigned(Control.OnMouseUp) then Exit;事件处理程序上执行OnClick

  2. 在分配OnClick时取消分配OnMouseUp事件(反之亦然)

  3. 这两种方法都将完成您详细说明的内容,但“取消分配”OnClick事件最适合性能(在极小范围内),因为您不会执行if语句反复。