简体   繁体   English

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

[英]Delphi pass object as parameter on click event

I have this code: 我有以下代码:

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

And then I have a procedure 然后我有一个程序

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

And I'm getting this error: 我收到此错误:

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

The error is because you are trying to call SetSidebarButtonActive() and then assign its result (which it has none) to the OnClick event. 该错误是因为您试图调用 SetSidebarButtonActive() ,然后将其结果(没有结果SetSidebarButtonActive()分配给OnClick事件。 That will not work. 那不管用。

The OnClick event is defined as a TNotifyEvent : OnClick事件定义为TNotifyEvent

TNotifyEvent = procedure(Sender: TObject) of object;

That means that 那意味着

  • the procedure needs to be a member of a class 该程序必须是课程的成员

  • you have to assign the address of the procedure to OnClick , not call the procedure 您必须将过程的地址分配给OnClick ,而不是调用过程

  • the procedure must take only 1 input parameter, which is the TObject that fires the event (in this case, the TPanel that is being clicked on). 该过程必须仅接受1个输入参数,这是引发事件的TObject (在这种情况下,是单击的TPanel )。

So, for what you are attempting, you would need to do something more like this instead: 因此,对于您尝试的操作,您将需要执行以下操作:

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;

Alternatively, you can store the TSidebarButton reference in the TPanel.Tag property (assuming you are not using it for something else): 另外,您可以将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;

Alternatively, you can define a helper class to provide you access to the TSidebarButton without looking at the TPanel at all: 另外,您可以定义一个帮助程序类以提供对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;

Alternatively, if you are creating the TPanel objects yourself inside of TSidebarButton , you could simply derive a new class from TPanel to add a TSidebarButton reference to it: 另外,如果您正在创建的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;

There are all kinds of options available to you. 您可以使用各种选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM