首页 > 解决方案 > 将父对象的事件绑定到临时子对象的方法

问题描述

我有一个应用程序,其中一个不可见的“主机”应用程序对象创建主窗体,主窗体临时创建一个数据监控对话框窗体。

“主机”中有一个异步数据接收器,它具有跟踪输出事件。该事件应在对话框表单存在时与数据监控对话框表单的方法临时绑定,在即将销毁时解除绑定。

我在下面做了一个与这个应用程序相同的最小化。你能检查一下这是否是正确的方法吗?请关注“注意”评论。

program BindToTempObject;

uses
  Vcl.Forms, System.Classes, Vcl.StdCtrls, Vcl.ExtCtrls, System.SysUtils;

type
  TBoolEvent = procedure(b: Boolean) of object;

  TDialogForm = class(TForm)
  public
    constructor Create(AOwner: TComponent); override;
    procedure BoolEventHandler(b: Boolean);
  end;

  TMainForm = class(TForm)
  private
    _btn: TButton;
    _onBoolEventRelay: TBoolEvent; //Attention
    procedure _btnClick(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    procedure BoolEventRelay(b: Boolean); //Attention
  end;

  TAppObject = class
  private
    _mainForm: TMainForm;
    _eventSource: TTimer;
    _boolState: Boolean;
    procedure _eventSourceTick(Sender: TObject);
  public
    OnBoolEvent: TBoolEvent;
    constructor Create();
    destructor Destroy(); override;
  end;

var
  app: TAppObject;

{ TAppObject }

constructor TAppObject.Create();
begin
  Application.CreateForm(TMainForm, _mainForm);
  OnBoolEvent := _mainForm.BoolEventRelay; //Attention
  _eventSource := TTimer.Create(nil);
  _eventSource.OnTimer := _eventSourceTick;
  _eventSource.Enabled := True;
end;

destructor TAppObject.Destroy();
begin
  _eventSource.OnTimer := nil;
  _eventSource.Free();
  inherited;
end;

procedure TAppObject._eventSourceTick(Sender: TObject);
begin
  _boolState := not _boolState;
  if Assigned(OnBoolEvent) then OnBoolEvent(_boolState);
end;

{ TMainForm }

constructor TMainForm.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  Caption := 'Main form';
  _btn := TButton.Create(Self);
  _btn.Parent := Self;
  _btn.Caption := 'Click me';
  _btn.OnClick := _btnClick;
end;

procedure TMainForm.BoolEventRelay(b: Boolean);
begin
  if Assigned(_onBoolEventRelay) then _onBoolEventRelay(b); //Attention
end;

procedure TMainForm._btnClick(Sender: TObject);
var
  dlg: TDialogForm;
begin
  dlg := TDialogForm.Create(Self);
  try
    _onBoolEventRelay := dlg.BoolEventHandler; //Attention
    dlg.ShowModal();
  finally
    _onBoolEventRelay := nil; //Attention
    dlg.Free();
  end;
end;

{ TDialogForm }

procedure TDialogForm.BoolEventHandler(b: Boolean);
begin
  Caption := BoolToStr(b, True);
end;

constructor TDialogForm.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  Caption := 'Dialog form';
end;

begin
  Application.Initialize();
  app := TAppObject.Create();
  try
    Application.Run();
  finally
    app.Free();
  end;
end.

标签: delphievent-handling

解决方案


你可以那样做,当然。类之间的职责分离得当,因此它们不必相互了解。

但是,在您的特定示例中,由于所有内容都在一个单元中,并且该app对象是全局可访问的,因此您可以通过将TDialogForm.BoolEventHandler()方法直接分配给TAppObject.OnBoolEvent事件并摆脱TMainForm中间人的身份来简化代码:

program BindToTempObject;

uses
  Vcl.Forms, System.Classes, Vcl.StdCtrls, Vcl.ExtCtrls, System.SysUtils;

type
  TBoolEvent = procedure(b: Boolean) of object;

  TDialogForm = class(TForm)
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy(); override;
    procedure BoolEventHandler(b: Boolean);
  end;

  TMainForm = class(TForm)
  private
    _btn: TButton;
    procedure _btnClick(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TAppObject = class
  private
    _mainForm: TMainForm;
    _eventSource: TTimer;
    _boolState: Boolean;
    procedure _eventSourceTick(Sender: TObject);
  public
    OnBoolEvent: TBoolEvent;
    constructor Create();
    destructor Destroy(); override;
  end;

var
  app: TAppObject;

{ TAppObject }

constructor TAppObject.Create();
begin
  Application.CreateForm(TMainForm, _mainForm);
  _eventSource := TTimer.Create(nil);
  _eventSource.OnTimer := _eventSourceTick;
  _eventSource.Enabled := True;
end;

destructor TAppObject.Destroy();
begin
  _eventSource.OnTimer := nil;
  _eventSource.Free();
  inherited;
end;

procedure TAppObject._eventSourceTick(Sender: TObject);
begin
  _boolState := not _boolState;
  if Assigned(OnBoolEvent) then OnBoolEvent(_boolState);
end;

{ TMainForm }

constructor TMainForm.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  Caption := 'Main form';
  _btn := TButton.Create(Self);
  _btn.Parent := Self;
  _btn.Caption := 'Click me';
  _btn.OnClick := _btnClick;
end;

procedure TMainForm._btnClick(Sender: TObject);
var
  dlg: TDialogForm;
begin
  dlg := TDialogForm.Create(Self);
  try
    dlg.ShowModal();
  finally
    dlg.Free();
  end;
end;

{ TDialogForm }

procedure TDialogForm.BoolEventHandler(b: Boolean);
begin
  Caption := BoolToStr(b, True);
end;

constructor TDialogForm.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  Caption := 'Dialog form';
  app.OnBoolEvent := BoolEventHandler;
end;

destructor TDialogForm.Destroy();
begin
  app.OnBoolEvent := nil;
  inherited;
end;

begin
  Application.Initialize();
  app := TAppObject.Create();
  try
    Application.Run();
  finally
    app.Free();
  end;
end.

推荐阅读