views:

185

answers:

4

I want to write some code that assigns the same event handler to several different buttons. Is there a way to implement it without referring to each button by name but by using something generic like self or sender to refer to the button?

+3  A: 

Yes. Every normal method call includes a hidden "Self" that refers to the object. But in an event handler, "Self" is the form, not the button. The button is Sender, and you'll have to typecast it using something like Sender as TButton.

Mason Wheeler
Isn't that a conversion? It does more that reintrepret memory.
Marco van de Voort
http://tech.turbu-rpg.com/56/as-sertion-casting **As** is a cast, not a conversion, but it checks to make sure you've got the type right and raises an exception otherwise.
Mason Wheeler
+2  A: 

You'll need to use sender.

(Sender as TButton).Enabled := False;

Would disable any button that has this event handler assigned to its onclick event. The cast can also be done

TButton(Sender).Enabled := False;

but in this case you need to be 100% that sender is a button. Using as introduces a check before the cast, so is slightly slower, but in this type of example is not really a problem I think.

Steve
As-casting basically walks a linked list from the object's actual type to the type you're casting to, looking for matches. If you do it in a tight loop and the "as type" is several levels of inheritance above the actual type, it can give a definite performance hit, but aside from that you'll probably never notice it.
Mason Wheeler
+1  A: 

You can do something like this:

procedure OnClickButton(Sender: TObject);
var btn: TButton;
begin
  if Sender is TButton then btn := TButton(mycontrol) 
  else
      exit;
  //and then use btn as just another button control
end;

and to assign the same event to different controls you could do:

if mycontrol is TButton then 
  TButton(mycontrol).OnClick := OnClickButton;
eKek0
+1  A: 

Consider 'disconnecting' yourself from buttons and use actions. Plonk an action list on your form, right-click it and 'add' and action. Name it, caption it (as if it were a button, say) and then wire up its OnExecute event to your code. Finally, go to your button and click on the 'Action' property and nominate your new action. When you click on the button, your code is executed.

Why is this useful? Well: 1. You will not lose access to your code, which commonly happens when you delete the button and replace it with, say, a TPopupMenu. 2. One action can be launched with way from several places, multiple buttons or menus. 3. Better still, fill in the action's 'OnUpdate' event with something like:

procedure TForm1.MyActionOnUpdate( ASender : TObject );
begin
  With Sender as TAction do
    Enabled := ItsPossibleToRunMyCode;
end;

This bit of code will enable and disable any control that uses this action without you needing to do anything.

Brian Frost