Delphi将对象作为单击事件的参数传递

时间:2019-05-10 19:19:30

标签: delphi

我有此代码:

for LSidebarButton in SidebarButtons do
  begin
    LSidebarOverlay := TPanel(LSidebarButton.Button.Controls[3]);
    LSidebarOverlay.OnClick := SetSidebarButtonActive(nil, LSidebarButton);
  end;

然后我有一个程序

procedure SetSidebarButtonActive(sender: TObject; btn: TSidebarButton);
begin
    btn.SetActive;
    //more code
end;

我收到此错误:

E2010 Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter'

1 个答案:

答案 0 :(得分:3)

该错误是因为您尝试调用 SetSidebarButtonActive(),然后将其结果(没有结果)分配给OnClick事件。那是行不通的。

OnClick事件被定义为TNotifyEvent

TNotifyEvent = procedure(Sender: TObject) of object;

那是

  • 该过程必须是一个类的成员

  • 您必须将过程的地址分配给OnClick,而不是 call 该过程

  • 过程必须仅接受1个输入参数,即触发事件的TObject(在这种情况下,单击的TPanel )。

因此,对于您要尝试的操作,您将需要执行以下操作:

procedure TMyForm.DoSomething;
var
  ...
  LSidebarButton: TSidebarButton;
  LSidebarOverlay: TPanel;
  ...
begin
  ...
  for LSidebarButton in SidebarButtons do
  begin
    LSidebarOverlay := TPanel(LSidebarButton.Button.Controls[3]);
    LSidebarOverlay.OnClick := SetSidebarButtonActive;
  end;
  ...
end;

procedure TMyForm.SetSidebarButtonActive(Sender: TObject);
var
  Pnl: TPanel;
  Btn: TSidebarButton;
begin
  Pnl := TPanel(Sender);

  Btn := (Pnl.Parent as TSidebarButton);
  // or maybe (Pnl.Parent.Parent as TSidebarButton)?
  // or maybe (Pnl.Owner as TSidebarButton)?
  // or maybe (Pnl.Parent.Owner as TSidebarButton)?
  // Hard to know with your example. Use whatever you
  // need to get back to the TSidebarButton from its
  // inner child TPanel...

  Btn.SetActive;
  ...
end;

或者,您可以将TSidebarButton引用存储在TPanel.Tag属性中(假设您没有将其用于其他用途)

procedure TMyForm.DoSomething;
var
  ...
  LSidebarButton: TSidebarButton;
  LSidebarOverlay: TPanel;
  ...
begin
  ...
  for LSidebarButton in SidebarButtons do
  begin
    LSidebarOverlay := TPanel(LSidebarButton.Button.Controls[3]);
    LSidebarOverlay.Tag := NativeInt(LSidebarButton);
    LSidebarOverlay.OnClick := SetSidebarButtonActive;
  end;
  ...
end;

procedure TMyForm.SetSidebarButtonActive(Sender: TObject);
var
  Btn: TSidebarButton;
begin
  Btn := TSidebarButton(TPanel(Sender).Tag);
  Btn.SetActive;
  ...
end;

或者,您可以定义一个帮助程序类,以提供对TSidebarButton的访问权限,而根本不用看TPanel

type
  TOverlayClickHelper = class(TComponent)
  public
    Button: TSidebarButton;
    procedure OnClick(Sender: TObject);
  end;

...

procedure SetSidebarButtonActive(Btn: TSidebarButton);
begin
  Btn.SetActive;
  //more code
end;

procedure TOverlayClickHelper.OnClick(Sender: TObject);
begin
  SetSidebarButtonActive(Button);
end;

procedure TMyForm.DoSomething;
var
  ...
  LSidebarButton: TSidebarButton;
  LSidebarOverlay: TPanel;
  Helper: TOverlayClickHelper;
  ...
begin
  ...
  for LSidebarButton in SidebarButtons do
  begin
    LSidebarOverlay := TPanel(LSidebarButton.Button.Controls[3]);
    Helper := TOverlayClickHelper(LSidebarOverlay.FindComponent('MyHelper'));
    if Helper = nil then
    begin
      Helper := TOverlayClickHelper.Create(LSidebarOverlay);
      Helper.Name := 'MyHelper';
    end;
    Helper.Button := LSidebarButton;
    LSidebarOverlay.OnClick := Helper.OnClick;
  end;
  ...
end;

或者,如果您要自己在TPanel内创建TSidebarButton对象,则可以简单地从TPanel派生一个新类,为其添加一个TSidebarButton引用:

type
  TSidebarButtonPanel = class(TPanel)
  public
    Button: TSidebarButton;
  end;

...

procedure TSidebarButton.CreateOverlay;
var
  LOverlay: TSidebarButtonPanel;
begin
  LOverlay := TSidebarButtonPanel.Create(Self);
  LOverlay.Parent := Self.Button;
  LOverlay.Button := Self;
  ...
end;

...

procedure TMyForm.DoSomething;
var
  ...
  LSidebarButton: TSidebarButton;
  LSidebarOverlay: TPanel;
  ...
begin
  ...
  for LSidebarButton in SidebarButtons do
  begin
    LSidebarOverlay := TPanel(LSidebarButton.Button.Controls[3]);
    LSidebarOverlay.OnClick := SetSidebarButtonActive;
  end;
  ...
end;

procedure TMyForm.SetSidebarButtonActive(Sender: TObject);
var
  Btn: TSidebarButton;
begin
  Btn := TSidebarButtonPanel(Sender).Button;
  Btn.SetActive;
  ...
end;

您可以使用各种选择。