开发者

Delphi: How to call a method when i click a control?

开发者 https://www.devze.com 2022-12-30 09:26 出处:网络
i have a method: procedure Frob(Sender: TObject); that i want to call when i click a menu item. The method comes to me though an interface:

i have a method:

procedure Frob(Sender: TObject);

that i want to call when i click a menu item.

The method comes to me though an interface:

animal: IAnimal;

IAnimal = interface
   procedure Frob(Sender: TObject);
end;

The question revolves around what to assign to the OnClick event handler of 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, my first attempt, and the wrong answer is:

   menuItem.OnClick := animal.Frob;

So how can i call a method when user clicks a control?

See also

  • Why doesn't it work?


Have whatever object you're in hold the animal in a private field, then set up a method that calls it. Like so:

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

Then the solution becomes easy:

menuItem.OnClick := self.AnimalFrob;


Another, slightly hackier approach would be to store a reference to the IAnimal in the Tag property of the TMenuItem.

This could be the index of the IAnimal in a TList as you suggested:

if Sender is TMenuItem then
  IAnimal(FAnimals[TMenuItem(Sender).Tag]).Frob;

Or you could cast the interface to Integer.

MenuItem.Tag := Integer(AnAnimal);

Then cast back to IAnimal in the event handler:

if Sender is TMenuItem then
  IAnimal(TMenuItem(Sender)).Frob;

This works well with Object references, some care may be required with interfaces due to the reference counting.

Note that Delphi 7 also has a TInterfaceList in Classes.pas


I know you tagged the question as answered, 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 lifetime of the "clicker" object...

If you can manipulate your objects as objects (and not only as interfaces), try adding a common subclass :

type
  TClicker = class
    procedure OnClick( Sender : TObject ); virtual;
  end;

var
  lClicker : TClicker;
...
menuItem.OnClick := lClicker.OnClick;

I would also go for Cosmin Prund's comment : make a specialized TMenuItem subclass.

0

精彩评论

暂无评论...
验证码 换一张
取 消