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

+1


a source to share


3 answers


Do you have an object where you keep the animal in a private field, then set up a method that calls it. For instance:

procedure TMyClass.AnimalFrob(Sender: TObject);
begin
   FAnimal.Frob(sender);
end;

      



Then the solution becomes easy:

menuItem.OnClick := self.AnimalFrob;

+4


a source


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

+1


a source


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.

+1


a source







All Articles