Delphi -为运行时创建的按钮添加onclick

mepcadol  于 2023-05-12  发布在  其他
关注(0)|答案(2)|浏览(228)

我有一个过程,它在运行时为传递给它的任何表单名称创建customtitlebartitlebarpanel。这样做的目的是自动处理一堆不同表单的创建,而不必担心当前表单控件的位置。此代码会自动将所有控件向下 Shuffle ,使它们不被titlebarpanel覆盖。
这个代码可以工作。从任何表单的oncreate调用此过程,都会在表单标题栏区域添加2个按钮。

procedure CreateTitleBarPanel(fname:tform);
var titlebarpanel:ttitlebarpanel;
    F1button,F12button:tspeedbutton;
    i:integer;
begin
     fname.customtitlebar.enabled:=true;
     titlebarpanel:=ttitlebarpanel.create(fname);
     titlebarpanel.parent:=fname;
     titlebarpanel.Visible:=true;
     fname.customtitlebar.control:=titlebarpanel;
     F1button:=tspeedbutton.create(titlebarpanel);
     F1button.parent:=titlebarpanel;
     F1button.top:=10;
     F1button.height:=fname.customtitlebar.height-15;
     F1button.width:=F1button.height;

     //this is the problem
     F1button.onclick:=how??

     F12button:=tspeedbutton.create(titlebarpanel);
     F12button.parent:=titlebarpanel;
     F12button.top:=10;
     F12button.height:=fname.customtitlebar.height-15;
     F12button.width:=F12button.height;
     F12button.left:=fname.customtitlebar.clientrect.width - F1button.Width - 8;
     F1button.left:=F12button.left - F1button.Width - 8;
     //move all form components down to match the titlebar height
     for i:=0 to fname.ComponentCount-1 do
     begin
          try
             (fname.Components[i] as TControl).top:=(fname.Components[i] as TControl).top+fname.customtitlebar.height;
          except
                //control does not have a top property, so skip it
          end;
     end;
end;

我的问题是,我想onclick按钮调用另一个过程中传递的fname,所以例如类似

F1button.onclick:=AnotherProcedure(fname);

但这不管用。E2010 Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter有人能解释一下我如何让它工作吗?在运行时创建的按钮,当单击它时,我希望它调用AnotherProcedure(fname);(如果有帮助的话,这个过程与CreateTitleBarPanel过程是相同的单元。
谢谢你的帮助

xv8emn3q

xv8emn3q1#

TSpeedButton.OnClick是一个事件处理程序(继承自Vcl.Controls.TControl.OnClick),其类型为TNotifyEvent
类型定义:

TNotifyEvent = procedure(Sender: TObject) of object;

这意味着您必须定义一个过程,接受对象(可以是您的表单或任何其他对象)上的TObject参数。例如:

TMyForm = class(TForm)
 public
   procedure MyOnClick(Sender : TObject);
 end;

...

procedure TMyForm.MyOnClick(Sender : TObject);
begin
  
end;

然后你就可以通过这种方式将它分配为按钮的OnClick事件处理程序:

F1button.OnClick := MyOnClick;
vsdwdz23

vsdwdz232#

你不能完全按照你写的去做。
按钮的OnClick事件是指向TNotifyEvent类型过程的链接。这意味着首先这个过程必须只有一个类型为TObject的参数,其次这个过程必须是某个对象的方法。
如果你想有和你写的类似的行为,你需要把这个方法添加到你传递到CreateTitleBarPanel()的每个表单中,并把它分配给你的按钮,或者你需要有一些全局对象,你的方法有指定的行为。就像这样:

type
  TMyButtonsClickHandler = class(TObject)
  public
    procedure DoButtonClick(Sender : TObject);
  end;

var      
  MyButtonsClickHandler : TMyButtonsClickHandler;

implementation  

{ TMyButtonsClickHandler }

procedure TMyButtonsClickHandler.DoButtonClick(Sender: TObject);
var
  fname : TCustomForm;
begin
  //Sender must by one of our buttons, make sure that
  if Sender is TSpeedButton then
  begin
    //get form of our button
    fname := GetParentForm(TSpeedButton(Sender), true);
    //calling your functionality with form object as IN param, as you ask
    AnotherProcedure(fname);
  end;
end;

initialization
  //create our global object before any calls
  MyButtonsClickHandler := TMyButtonsClickHandler.Create;

finalization
  //destroy our global object in finalization
  FreeAndNil(MyButtonsClickHandler);

end.

当你拥有这个全局对象时,你可以在你的CreateTitleBarPanel()函数中创建F1button.OnClick := MyButtonsClickHandler.DoButtonClick;,然后点击这些按钮中的任何一个,将运行你的AnotherProcedure(),并将父窗体作为参数。

相关问题