Delphi: How do I call a method when I click on a control?
I have a method:
procedure Frob(Sender: TObject);
which I want to call when I click a menu item.
The method comes to me though the interface is:
animal: IAnimal;
IAnimal = interface
procedure Frob(Sender: TObject);
end;
The question revolves around what to assign to an event handler OnClick
for a menu item (i.e. control):
var
animal: IAnimal;
...
begin
...
menuItem := TMenuItem.Create(FileMenu)
menuItem.Caption := 'Click me!';
menuItem.OnClick := <-------- what to do
...
end;
The obvious choice for my first try, and the wrong answer is :
menuItem.OnClick := animal.Frob;
So how can a method be called when the user clicks the control?
see also
a source to share
Another, slightly hacky approach would be to store the reference to the TMenuItem IAnimal
property Tag
.
It could be the IAnimal index in the TList, as you suggested:
if Sender is TMenuItem then
IAnimal(FAnimals[TMenuItem(Sender).Tag]).Frob;
Or you can apply the interface to Integer.
MenuItem.Tag := Integer(AnAnimal);
Then switch back to IAnimal in your event handler:
if Sender is TMenuItem then
IAnimal(TMenuItem(Sender)).Frob;
This works well with object references, some may be required with interfaces due to reference counting.
Note that Delphi 7 also has a TInterfaceList in Classes.pas
a source to share
I know you marked the question as an answer, but here are some other suggestions:
type
IClicker = Interface
function GetOnClickProc : TNotifyEvent;
End;
type
TBlob = class( TInterfacedObject, IClicker )
procedure OnClick( Sender : TObject );
function GetOnClickProc : TNotifyEvent;
end;
{ TBlob }
function TBlob.GetOnClickProc : TNotifyEvent;
begin
Result := Self.OnClick;
end;
procedure TBlob.OnClick(Sender: TObject);
begin
MessageDlg('Clicked !', mtWarning, [mbOK], 0);
end;
{ MyForm }
var
clicker : IClicker;
begin
...
menuItem.OnClick := clicker.GetOnClickProc;
end;
Of course, you have to be careful about the life of the clicker object ...
If you can manipulate objects as objects (and not just as interfaces), try adding a generic subclass:
type
TClicker = class
procedure OnClick( Sender : TObject ); virtual;
end;
var
lClicker : TClicker;
...
menuItem.OnClick := lClicker.OnClick;
I would go to Cosmin Prund's comment too: Create a custom subclass of TMenuItem.
a source to share