views:

320

answers:

2

When I make a dynamic component from unit I have no problem creating the OnClick event. When I make a dynamic component from unit 2 I am unable to access the OnClick event.

unit Unit1  
type  
    TForm1 = class(TForm)  
      procedure FormCreate(Sender: TObject);  
    private  
      { Private declarations }  
    public  
      Procedure ClickBtn1(Sender: TObject);  
    end;  

var  
    Form1: TForm1;  
    MyBtn1: TButton;  
implementation  

{$R *.dfm}

{ TForm1 }
uses Unit2;

procedure TForm1.ClickBtn1;  
begin  
    MyBtn1.Caption := 'OK';  
    MakeBtn2;  
end;


procedure TForm1.FormCreate(Sender: TObject);  
begin  
    MyBtn1 := TButton.Create(Self);  
    MyBtn1.Parent := Form1;  
    MyBtn1.Name := 'Btn1';  
    MyBtn1.Left := 50;  
    MyBtn1.Top := 100;  
    MyBtn1.Caption := 'Click Me';  
    MyBtn1.OnClick := ClickBtn1;  
end;  


end.



unit Unit2;

interface

uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls;

procedure MakeBtn2;  
procedure ClickBtn2;      
var  
    MyBtn2: TButton;  

implementation

Uses Unit1;

procedure MakeBtn2;  
begin  
    MyBtn2 := TButton.Create(Form1);  
    MyBtn2.Parent := Form1;  
    MyBtn2.Name := 'Btn2';  
    MyBtn2.Left := 250;  
    MyBtn2.Top := 100;  
    MyBtn2.Caption := 'Click Me';  
    MyBtn2.OnClick := ClickBtn2;    //Compiler ERROR
end;  

procedure ClickBtn2;  
begin  
    MyBtn1.Caption := 'OK';  
end;  
end.
+1  A: 

Are you sure the first example works? Neither of these should compile.

An OnClick handler is a TNotifyEvent, which is defined as

procedure(Sender: TObject) of object;

That means that it has to be a method of an object (such as a form), and the method signature has to be a procedure that takes a single TObject parameter. Your procedure MakeBtn2 isn't an object method, and neither of them takes Sender: TObject.

Mason Wheeler
What would be the best way to acheive what I want?
Brian Heard
Declare a method on your form with the correct signature, and put the code you're trying to execute in there.
Mason Wheeler
+2  A: 

Have a look at this article "Creating A Component at Runtime"

Quote:

I want to create a button in code, put it on a form and attach a procedure to its click event. How can I get the click event linked to a predefined procedure name from code? I assume the IDE linking in the object browser is key to the answer, but I want to do this at run time, not in development.

First of all, you can assign any object's method to another method as long as it has the same form. Look at the code below:

{This method is from another button that when pressed will create
 the new button.}
procedure TForm1.Button1Click(Sender: TObject);
var
  btnRunTime : TButton;
begin
  btnRunTime := TButton.Create(form1);
  with btnRunTime do begin
    Visible := true;
    Top := 64;
    Left := 200;
    Width := 75;
    Caption := 'Press Me';
    Name := 'MyNewButton';
    Parent := Form1;
    OnClick := ClickMe;
  end;
end;

{This is the method that gets assigned to the new button's OnClick method}
procedure TForm1.ClickMe(Sender : TObject);
begin
  with (Sender as TButton) do
    ShowMessage('You clicked me');
end;

As you can see, I created a new method called ClickMe, which was declared in the private section of Form1:

type
  TForm1 = class(TForm
  ...
  ...
  private
    procedure ClickMe(Sender : TObject);
  published
  end;

For other examples and explanations see also the following:

Adrian