Delphi pass object as parameter on click event - delphi

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. That will not work.
The OnClick event is defined as a 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
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).
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):
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:
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:
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.

Related

Defining a component to have a name prefix different than its ClassName (minus the "T")

In Delphi, when the IDE inserts a new component at design time, it gives its name a prefix which is the ClassName minus the leading "T" and then adds a number that makes its name unique.
This recent question asks how to change the prefix part of the component's name, so that
Edit1
could be changed to
ed1
The accepted answer refers to the "rename components" utility in GExperts, which is fine so far as it goes.
However, is there a way I can always get the same, non-standard, prefix for a component without having to create and install a descendant component in the Componxent Palette? I know how to do this but it is an unwelcome chore if I want to do it for more than one component.
I noticed that Q&A, too.
It seemed to me to be a special case of something I wrote an answer for, how to specify
defaults for the properties of components added to a form. It is rather long-winded
and doesn't work for the component's Name property. However, it can be made to work
for the Name, too, with some quite minor modifications, so that it will now support a specfication
of defaults like this:
[TMemo]
Lines.Strings=
[TEdit]
Font.Name=Courier New
Font.Size=11
[TButton]
Name=btn
Caption=
[TCheckBox]
Name=cb
Caption=
Note that the TButton and TCheckBox use non-standard Name prefixes and a blank Caption.
The blank Caption is to save having to rub out the default the IDE provides.
The full code of the unit which needs to be added to a design-time package and installed in the IDE is below. The main change,
compared to my previous answer, is that the component's Name property is handled separately from
any other properties by this
procedure TDesignNotifierForm.SetComponentName(AComponent : TComponent; AComponentName : String);
var
AOwner : TComponent;
begin
// First, try to find the component's Form. We need this so that we can ask the Form's
// Designer to generate a unique name for the component instance (Comp1, Comp2, etc).
AOwner := AComponent.Owner;
while (AOwner <> Nil) and not(AOwner is TForm) do
AOwner := AOwner.Owner;
if AOwner is TForm then begin
AComponentName := TForm(AOwner).Designer.UniqueName(AComponentName);
AComponent.Name := AComponentName;
TForm(AOwner).Designer.Modified; // Notify the Form's Designer
end;
end;
procedure TDesignNotifierForm.SetComponentProperties(AComponent : TComponent; ComponentClassName : String);
var
i : Integer;
AString : String;
Index : Integer;
begin
// Note: The defaults which can be set include the Component's Name. For simplicity, it can be included
// amongst the other defaults but requires special treatment (see SetComponentName).
//
if Ini.SectionExists(ComponentClassName) then begin
Ini.ReadSectionValues(ComponentClassName, SL);
Index := SL.IndexOfName('Name');
if Index >= 0 then begin
AString := SL.Values['Name'];
SetComponentName(AComponent, AString);
end;
for i := 0 to SL.Count - 1 do begin
if i <> Index then begin
AString := ComponentClassName + '.' + SL[i];
SetComponentProperty(AComponent, AString);
end;
end;
end;
end;
Unit code:
unit DesignNotifierFormu;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, TypInfo, ToolsApi, DesignIntf, IniFiles;
const
WM_CompInserted = WM_User + 1;
type
TDesignNotifierForm = class(TForm)
Memo1: TMemo;
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
procedure SetComponentProperties(AComponent : TComponent; ComponentClassName: String);
procedure SetComponentName(AComponent: TComponent; AComponentName: String);
public
AComp : TComponent;
Ini : TMemIniFile;
SL : TStringList;
procedure Log(const Title, Msg : String);
procedure WMCompInserted(var Msg : TMsg); message WM_CompInserted;
end;
TDesignNotification = class(TInterfacedObject, IDesignNotification)
F : TDesignNotifierForm;
procedure ItemDeleted(const ADesigner: IDesigner; AItem: TPersistent);
procedure ItemInserted(const ADesigner: IDesigner; AItem: TPersistent);
procedure ItemsModified(const ADesigner: IDesigner);
procedure SelectionChanged(const ADesigner: IDesigner;
const ASelection: IDesignerSelections);
procedure DesignerOpened(const ADesigner: IDesigner; AResurrecting: Boolean);
procedure DesignerClosed(const ADesigner: IDesigner; AGoingDormant: Boolean);
constructor Create;
destructor Destroy; override;
end;
var
DesignNotification : TDesignNotification;
implementation
{$R *.dfm}
constructor TDesignNotification.Create;
begin
inherited Create;
F := TDesignNotifierForm.Create(Nil);
F.Show;
F.Log('Event', 'Notifier created');
end;
procedure TDesignNotification.DesignerClosed(const ADesigner: IDesigner;
AGoingDormant: Boolean);
begin
end;
procedure TDesignNotification.DesignerOpened(const ADesigner: IDesigner;
AResurrecting: Boolean);
var
C : TComponent;
Msg : String;
begin
EXIT; // following for experimenting only
C := ADesigner.Root;
if C <> Nil then begin
Msg := C.ClassName;
// At this point, you can call ShowMessage or whatever you like
ShowMessage(Msg);
end
else
Msg := 'no root';
F.Log('Designer Opened', Msg);
end;
destructor TDesignNotification.Destroy;
begin
F.Close;
F.Free;
inherited;
end;
procedure TDesignNotification.ItemDeleted(const ADesigner: IDesigner;
AItem: TPersistent);
begin
end;
procedure TDesignNotification.ItemInserted(const ADesigner: IDesigner;
AItem: TPersistent);
var
S : String;
begin
if AItem is TComponent then begin
S := 'Component name: ' + TComponent(AItem).Name;
F.AComp := TComponent(AItem);
PostMessage(F.Handle, WM_CompInserted, 0, 0);
end
else
S := 'Item';
F.Log('Designer', ADesigner.GetComponentName(TComponent(AItem)));
F.Log('ItemInserted', S);
end;
procedure TDesignNotification.ItemsModified(const ADesigner: IDesigner);
begin
end;
procedure TDesignNotification.SelectionChanged(const ADesigner: IDesigner;
const ASelection: IDesignerSelections);
begin
end;
procedure SetUp;
begin
DesignNotification := TDesignNotification.Create;
RegisterDesignNotification(DesignNotification);
end;
procedure TDesignNotifierForm.FormCreate(Sender: TObject);
begin
Ini := TMemIniFile.Create('d:\aaad7\ota\componentdefaults\defaults.ini');
SL := TStringList.Create;
end;
procedure TDesignNotifierForm.FormDestroy(Sender: TObject);
begin
SL.Free;
Ini.Free;
end;
procedure SplitStr(const Input, Delim : String; var Head, Tail : String);
var
P : Integer;
begin
P := Pos(Delim, Input);
if P = 0 then begin
Head := Input;
Tail := '';
end
else begin
Head := Copy(Input, 1, P - 1);
Tail := Copy(Input, P + Length(Delim), MaxInt);
end;
end;
procedure SetComponentProperty(AComponent : TComponent; AString : String);
var
Value,
Head,
Tail,
ObjName,
PropName : String;
Obj : TObject;
AType : TTypeKind;
begin
// needs to Use TypInfo
SplitStr(AString, '=', PropName, Value);
if PropName = '' then else;
SplitStr(PropName, '.', Head, Tail);
if Pos('.', Tail) = 0 then begin
SetStrProp(AComponent, Tail, Value);
end
else begin
SplitStr(Tail, '.', ObjName, PropName);
Obj := GetObjectProp(AComponent, ObjName);
if Obj is TStrings then begin
// Work around problem setting e.g. TMemo.Lines.Text
TStrings(Obj).Text := Value;
end
else begin
AType := PropType(Obj, PropName);
case AType of
// WARNING - incomplete list
tkString,
tkLString : SetStrProp(Obj, PropName, Value);
tkInteger : SetOrdProp(Obj, PropName, StrToInt(Value));
tkFloat : SetFloatProp(Obj, PropName, StrToFloat(Value));
end; { case }
end;
end;
end;
procedure TDesignNotifierForm.SetComponentName(AComponent : TComponent; AComponentName : String);
var
AOwner : TComponent;
begin
// First, try to find the component's Form. We need this so that we can ask the Form's
// Designer to generate a unique name for the component instance (Comp1, Comp2, etc).
AOwner := AComponent.Owner;
while (AOwner <> Nil) and not(AOwner is TForm) do
AOwner := AOwner.Owner;
if AOwner is TForm then begin
AComponentName := TForm(AOwner).Designer.UniqueName(AComponentName);
AComponent.Name := AComponentName;
TForm(AOwner).Designer.Modified; // Notify the Form's Designer
end;
end;
procedure TDesignNotifierForm.SetComponentProperties(AComponent : TComponent; ComponentClassName : String);
var
i : Integer;
AString : String;
Index : Integer;
begin
// Note: The defaults which can be set include the Component's Name. For simplicity, it can be included
// amongst the other defaults but requires special treatment (see SetComponentName).
//
if Ini.SectionExists(ComponentClassName) then begin
Ini.ReadSectionValues(ComponentClassName, SL);
Index := SL.IndexOfName('Name');
if Index >= 0 then begin
AString := SL.Values['Name'];
SetComponentName(AComponent, AString);
end;
for i := 0 to SL.Count - 1 do begin
if i <> Index then begin
AString := ComponentClassName + '.' + SL[i];
SetComponentProperty(AComponent, AString);
end;
end;
end;
end;
procedure TDesignNotifierForm.WMCompInserted(var Msg: TMsg);
var
S : String;
begin
if AComp <> Nil then
S := AComp.Name
else
S := 'Name not known';
Log('WMCompInserted', S);
SetComponentProperties(AComp, AComp.ClassName);
AComp := Nil; // We're done with AComp
end;
procedure TDesignNotifierForm.Log(const Title, Msg: String);
begin
if csDestroying in ComponentState then
exit;
Memo1.Lines.Add(Title + ': ' + Msg);
end;
initialization
SetUp;
finalization
if DesignNotification <> Nil then begin
UnRegisterDesignNotification(DesignNotification);
end;
end.

Communicating between frames in Delphi

I just started using Frames in Delphi.
That Frames are in FrameBar1 and they both are visible. Just for testing, first one contains one Button and second Frame contains one Edit.
I want to change text in Edit with click on Button (which are controls on two different frames).
How to communicate between frames?
The same way you would if the controls were in the same Form. Just prefix the Edit control with the Frame object that owns it, eg:
uses
Frame1Unit, Frame2Unit;
procedure TForm1.FormCreate(Sender: TObject);
begin
Frame1 := TFrame1.Create(Self);
Frame1.Parent := ...;
...
Frame2 := TFrame2.Create(Self);
Frame2.Parent := ...;
...
end;
uses
Frame2Unit;
procedure TFrame1.Button1Click(Sender: TObject);
begin
Frame2.Edit1.Text := '...';
end;
A better design would be to encapsulate the logic so Frame1 and Frame2 do not know about each other. Have Frame1 expose an event that it fires when the button is clicked, and then the parent Form can assign a handler to that event and assign the text on the Frame2, eg:
uses
Frame1Unit, Frame2Unit;
procedure TForm1.FormCreate(Sender: TObject);
begin
Frame1 := TFrame1.Create(Self);
Frame1.Parent := ...;
Frame1.OnNewText := Frame1Text;
...
Frame2 := TFrame2.Create(Self);
Frame2.Parent := ...;
...
end;
procedure TForm1.Frame1Text(Sender: TObject; const NewText: string);
begin
Frame2.EditText := NewText;
end;
type
TFrame1TextEvent = procedure(Sender: TObject; const NewText; string) of object;
TFrame1 = class(TFrame)
Button1: TButton;
procedure Button1Click(Sender: TObject);
public
OnNewText: TFrame1TextEvent;
end;
procedure TFrame1.Button1Click(Sender: TObject);
begin
if Assigned(OnNewText) then
OnNewText(Self, '...');
end;
type
TFrame2 = class(TFrame)
Edit1: TEdit;
private
function GetEditText: string;
procedure SetEditText(const Value: string);
public
property EditText: string read GetEditText write SetEditText;
end;
function TFrame2.GetEditText: string;
begin
Result := Edit1.Text;
end;
procedure TFrame2.SetEditText(const Value: string);
begin
Edit1.Text := Value;
end;

How to make GIF animate on "please, wait form"?

I would like make a quick non-closable modal dialog, that pops up while do some tasks and goes away when tasks finish.
There are some inherent difficulties:
Don't block the main UI thread;
Don't leave system ghosts windows;
Move tasks to running into a separate thread;
Allow update the waiting message to the user;
Handling exceptions from thread to the application;
Show animated GIF in the dialog;
How to get around these pitfalls?
Below, a practical example of how I would use it:
TWaiting.Start('Waiting, loading something...');
try
Sleep(2000);
TWaiting.Update('Making something slow...');
Sleep(2000);
TWaiting.Update('Making something different...');
Sleep(2000);
finally
TWaiting.Finish;
end;
type
TWaiting = class(TForm)
WaitAnimation: TImage;
WaitMessage: TLabel;
WaitTitle: TLabel;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
strict private
class var FException: Exception;
private
class var WaitForm : TWaiting;
class procedure OnTerminateTask(Sender: TObject);
class procedure HandleException;
class procedure DoHandleException;
public
class procedure Start(const ATitle: String; const ATask: TProc);
class procedure Status(AMessage : String);
end;
implementation
{$R *.dfm}
procedure TWaiting.FormCreate(Sender: TObject);
begin
TGIFImage(WaitAnimation.Picture.Graphic).Animate := True;
end;
procedure TWaiting.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
class procedure TWaiting.Start(const ATitle: String; const ATask: TProc);
var
T : TThread;
begin
if (not Assigned(WaitForm))then
WaitForm := TWaiting.Create(nil);
T := TThread.CreateAnonymousThread(
procedure
begin
try
ATask;
except
HandleException;
end;
end);
T.OnTerminate := OnTerminateTask;
T.Start;
WaitForm.WaitTitle.Caption := ATitle;
WaitForm.ShowModal;
DoHandleException;
end;
class procedure TWaiting.Status(AMessage: String);
begin
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
if (Assigned(WaitForm)) then
begin
WaitForm.WaitMessage.Caption := AMessage;
WaitForm.Update;
end;
end);
end;
class procedure TWaiting.OnTerminateTask(Sender: TObject);
begin
if (Assigned(WaitForm)) then
begin
WaitForm.Close;
WaitForm := nil;
end;
end;
class procedure TWaiting.HandleException;
begin
FException := Exception(AcquireExceptionObject);
end;
class procedure TWaiting.DoHandleException;
begin
if (Assigned(FException)) then
begin
try
if (FException is Exception) then
raise FException at ReturnAddress;
finally
FException := nil;
ReleaseExceptionObject;
end;
end;
end;
end.
Usage:
procedure TFSales.FinalizeSale;
begin
TWaiting.Start('Processing Sale...',
procedure
begin
TWaiting.Status('Sending data to database');
Sleep(2000);
TWaiting.Status('Updating Inventory');
Sleep(2000);
end);
end;

Delphi passing Types in parameters

an example, I need to do this to solve a problem in a framework I am developing :
//Unit2 :
procedure A(aForm : TForm; AClassType: TFormClass);
begin
ShowMessage (AClassType(aForm).edtUser.text);
end;
...
//Unit1 :
Uses Unit2;
begin
form1 := TForm1.Create;
Try
A(form1, TForm1);
Finally
form1.Free;
End;
end;
The compiler does not accept this line:
AClassType (aform).edtUser.text
One solution would be to use:
Uses
UnitofTForm1;
The procedure (aform: TForm; AClassType: TForm1);
begin
ShowMessage (AClassType (aform).edtUser.text);
end;
But I can not do so because they are giving circular reference and I need some decoupling in my framework
Is there any way to make typecast passing as parameter the type of form or is there another way to do this ?
What you are asking for can be done by either:
deriving the various Form classes from a common base class that exposes the field you want to access:
procedure A(aForm : TBaseForm);
begin
ShowMessage(aForm.edtUser.Text);
end;
type
TBaseForm = class(TForm)
edtUser: TEdit;
...
end;
TDerivedForm = class(TBaseForm)
...
end;
...
frm := TDerivedForm.Create;
try
A(frm);
finally
frm.Free;
end;
or, use Generics:
type
TBaseForm = class(TForm)
edtUser: TEdit;
...
end;
TMyClass = class
class procedure A<T: TBaseForm>(aForm : T);
end;
class procedure TMyClass.A<T>(aForm : T);
begin
ShowMessage(aForm.edtUser.Text);
end;
frm := TDerivedForm.Create;
try
A<TDerivedForm>(frm);
finally
frm.Free;
end;
if a common base class is not possible, use an interface instead:
type
IMyFormAccess = interface
function GetUserText: string;
end;
procedure A(aForm : IMyFormAccess);
begin
ShowMessage(aForm.GetUserText);
end;
type
TForm1 = class(TForm, IMyFormAccess)
...
function GetUserText: string;
...
end;
function TForm1.GetUserText: string;
begin
Result := edtUser.Text;
end;
...
frm := TForm1.Create;
try
A(frm as IMyFormAccess);
finally
frm.Free;
end;
or, use legacy RTTI (only works with published properties):
uses
TypInfo;
procedure A(aForm : TForm);
var
Edt: TEdit;
begin
Edt := TEdit(GetObjectProp(aForm, 'edtUser', TEdit));
if Edt <> nil then
ShowMessage(Edt.Text);
end;
frm := TForm1.Create;
try
A(frm);
finally
frm.Free;
end;
or, use extended RTTI (works with all fields and visibility):
uses
System.Rtti;
procedure A(aForm : TForm);
var
Ctx: TRttiContext;
Fld: TRttiField;
Value: TValue;
Edt: TEdit;
begin
Fld := Ctx.GetType(aForm.ClassType).GetField('edtUser');
if Fld <> nil then
begin
Value := Fld.GetValue(aForm);
if (not Value.IsEmpty) and Value.IsObject then
begin
Edt := Value.AsObject as TEdit;
ShowMessage(Edt.Text);
end;
end;
end;
frm := TForm1.Create;
try
A(frm);
finally
frm.Free;
end;

How do I pass an event as a function parameter?

I have a form that has a list of useful procedures that I have created, that I often use in every project. I am adding a procedure that makes it simple to add a click-able image over where would be the TAccessory of a TListBoxItem. The procedure intakes the ListBox currently, but I would also need it to intake which procedure to call for the OnClick Event for the image.. Here is my existing code:
function ListBoxAddClick(ListBox:TListBox{assuming I need to add another parameter here!! but what????}):TListBox;
var
i : Integer;
Box : TListBox;
BoxItem : TListBoxItem;
Click : TImage;
begin
i := 0;
Box := ListBox;
while i <> Box.Items.Count do begin
BoxItem := Box.ListItems[0];
BoxItem.Selectable := False;
Click := Timage.Create(nil);
Click.Parent := BoxItem;
Click.Height := BoxItem.Height;
Click.Width := 50;
Click.Align := TAlignLayout.alRight;
Click.TouchTargetExpansion.Left := -5;
Click.TouchTargetExpansion.Bottom := -5;
Click.TouchTargetExpansion.Right := -5;
Click.TouchTargetExpansion.Top := -5;
Click.OnClick := // this is where I need help
i := +1;
end;
Result := Box;
end;
The desired procedure would be defined in the form that is calling this function.
Since the OnClick event is of type TNotifyEvent you should define a parameter of that type. Look at this (I hope self-explaining) example:
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
private
procedure TheClickEvent(Sender: TObject);
end;
implementation
procedure ListBoxAddClick(ListBox: TListBox; OnClickMethod: TNotifyEvent);
var
Image: TImage;
begin
Image := TImage.Create(nil);
// here is assigned the passed event method to the OnClick event
Image.OnClick := OnClickMethod;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
// here the TheClickEvent event method is passed
ListBoxAddClick(ListBox1, TheClickEvent);
end;
procedure TForm1.TheClickEvent(Sender: TObject);
begin
// do something here
end;

Resources