Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


Tip of the Day
Language: Pascal
Expertise: Beginner
May 9, 1997

Creating control from code in Delphi

Question:
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.

Here is a sample of my code:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
 var x : tbutton;
begin
x := tbutton.Create(form1);
x.visible := true;
x.top := 200;
x.left := 25;
x.width := 400;
x.caption := 'I am a brand new button';
x.name := 'button2';
x.parent := form1;

end;
procedure tform1.Button2Click(Sender: TObject);
begin
  showmessage ('cool');
 end;

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
 var x : tbutton;
begin
x := tbutton.Create(form1);
x.visible := true;
x.top := 200;
x.left := 25;
x.width := 400;
x.caption := 'I am a brand new button';
x.name := 'button2';
x.parent := form1;

end;
procedure tform1.Button2Click(Sender: TObject);
begin
  showmessage ('cool');
 end;
Clicking on the new button does nothing. Help!

Answer:
Thank God for object-oriented environments! You're doing everything pretty much correctly, but there's one thing you should know: 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;
There's no way to write code at run time, so it has to pre-exist. Fortunately with Delphi, you can perform re-assignment of methods to other methods in code. This duplicates assigning all the OnClick methods of a bunch of buttons to a single button's OnClick that you can do in the Object Inspector. You're just doing it in code.

So why does this work?

Event handlers are really nothing more than pointers to procedures. In the object code, they're declared something like the following:

type 
 TNotifyEvent = procedure(Sender : TObject) of object;
 TMouseEvent = procedure (Sender: TObject; Button: TMouseButton; Shift:
TShiftState; X, Y: Integer) of object;
Then, properties in the components are assigned these types. For instance, an OnClick for a button as seen in the Object Inspector is a TNotifyEvent and is declared in the component code as follows:
property OnClick : TNotifyEvent read FOnClick write FOnClick;
All this means is: When this event occurs, execute a method that has the structure that's what I'm expecting (the FOnClick var). In the case of OnClick, it's a method that has a single parameter of TObject — (Sender : TObject). Note that I specifically say "method," which implies that the procedure must be a member function of some object (like a form or another button), and not a generic procedure.

Regarding to the FOnClick, that's just a variable with the same type as the property; as such, it can be assigned any method that has the right structure.

In some but not all components, there's underlying behavior associated with any event that's performed by Windows message handlers. For instance, sometimes it's not enough just to declare an event handler. A button also gets its "button-ness" from the Windows messages it traps as well. For an OnClick, the specific Windows message is WM_LBUTTONUP (OnClick in the help is explained as an event that occurs when the user presses the mouse button down and releases it, which is why the user code is not executed until the button is released), and that is handled in the component code behind the scenes. It executes regardless of the code you assign to the OnClick procedure, and it is executed first. So here's pecking order:

  1. User clicks on a button.
  2. Windows Message code gets executed to ellicit default behavior for the component.
  3. Any code assigned to the user event handler is then executed by a specific Windows message handler.

This is stuff you don't normally hear about, and it's important to understand the intricacies behind why something works the way it does as opposed to me just giving you a "pat" answer. What I've essentially outlined here is the way in which an event handler is created. If you want more information, I suggest you get a book that deals with this. Ray Konopka's book Building Delphi Components (or something like that) is a good reference.

DevX Pro
 
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date