将父对象的事件绑定到临时子对象的方法

时间:2019-08-06 14:08:25

标签: delphi event-handling

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

“主机”中有一个异步数据接收器,具有跟踪输出事件。当对话框存在时,此事件应与数据监视对话框窗体的方法临时绑定,而在将其销毁时取消绑定。

我在下面最小化了此应用程序。您能检查一下这样做是否正确吗?请注意“注意”注释。

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.

1 个答案:

答案 0 :(得分:1)

您肯定可以那样做。班级之间的职责分工合理,因此他们不必彼此了解。

但是,在您的特定示例中,由于所有内容都在一个单元中,并且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.