Search code examples
delphieventhandler

Delphi - Adding onclick to a button created at runtime


I have a procedure that creates a customtitlebar and titlebarpanel at runtime for any form name passed to it. The purpose of this is to handle the creation automatically for a bunch of different forms without having to worry about the current form control positions. This code shuffles all controls down automatically so they are not covered by the titlebarpanel.

This code works. Call this procedure from any form's oncreate adds 2 buttons to the form titlebar area.

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;

My issue is that I want the onclick for the buttons to call another procedure passing in the fname, so eg something like

F1button.onclick:=AnotherProcedure(fname);

That doesn't work though. E2010 Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter Can anyone explain how I can get this to work? Button created at runtime, when clicked I want it to call AnotherProcedure(fname); (this procedure is the same unit as the CreateTitleBarPanel procedure if that helps.

Thanks for any help.


Solution

  • You can't do it exactly as you wrote.

    A button's OnClick event is a link to a procedure with type TNotifyEvent. That means that first of all this procedure must have only one parameter with type TObject, and second this procedure must be a method of some object.

    If you want to have similar behavior as you wrote - you need to add this method to every form that you pass into CreateTitleBarPanel() and assign it to your buttons, or you need to have some global object with your method with specified behavior. Something like that:

    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.
    

    When you will have this global object, you can make F1button.OnClick := MyButtonsClickHandler.DoButtonClick; inside your CreateTitleBarPanel() function, and then click on any of these buttons will run your AnotherProcedure() with the parent form as the parameter.