How can I see who triggered an action in Delphi?

倖福魔咒の 提交于 2019-12-03 02:10:55
Ville Krumlinde

Try using the ActionComponent property:

Stores the client component that caused this action to execute.

Use ActionComponent to discern which client component caused this action to execute. For example, examine ActionComponent from an OnExecute event handler if you need to know what user action triggered this action.

When the user clicks a client control, that client sets ActionComponent before calling the action's Execute method. After the action executes, the action resets ActionComponent to nil.

For example:

  ShowMessage( (Sender as TAction).ActionComponent.Name );

Using this I get "Button1" and "Button2" when I click the first and second button respectively.

Knowing what button triggered the action sort of goes against the point of using actions - an action may be triggered by a button click, or a menu click, or any number of other user activities. Actions exist to unify the state management of enable/disabled and click handling between buttons and menus.

If you want to know which button fired the action because you want to perform a slightly different operation, or "flavor" the operation differently, then perhaps TAction isn't the right solution for what you want to do.

Instead of actions, just use a click event. Set all buttons to use the same event handler. Ideally, NOT named after the first button (you can rename it).

Here's the code:

Procedure TMyForm.DestinationButtonClickHandlerThing(Sender: TObject); 
begin
  if Sender = Btn_ViewIt then
  begin
    // View It
  end
  else if Sender = Btn_FaxIt then
  begin
    // Fax It
  end
  else if Sender = Btn_ScrapIt then
  begin
    // Scrap It
  end
  else 
    ....   // error
   ...
end;

There are situations where the same action should apply to similar controls. The problem with

ShowMessage( (Sender as TAction).ActionComponent.Name );

is that when the action is invoked by a say popup menu, you get the popup menu's name. You could use:

procedure TMyForm.actMyActionExecute(Sender: TObject);
var
  LMyControl: TMyControl;
begin
  if Screen.ActiveControl.Name = 'MyControl1' then
    LMyControl = Sender as TMyControl
  else
    Exit;
  // Use the local variable for whatever needed
end;

Ok, in the meanwhile I think I found a workable solution..

I can have all controls use the same action; I just need to override their OnClick event handler, and I just need a single handler for all of them.

I'm still interested to know if it's possible to find out which control triggered the action, but for my current application I'm using a solution that's similar to the code below:

unit Example;

interface

uses
  Windows, Classes, Forms, Dialogs, Controls, ActnList, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    actDoStuff: TAction;
    procedure actDoStuffExecute(Sender: TObject);
    procedure ButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.actDoStuffExecute(Sender: TObject);
begin
  ShowMessage('Button '+TControl(Sender).Name +' was clicked')
end;

procedure TForm1.ButtonClick(Sender: TObject);
begin
  actDoStuffExecute(Sender)
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.OnClick := ButtonClick;
  Button2.OnClick := ButtonClick
end;

end.

set the Tag of the buttons as 1, 2, ... etc and then:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.OnClick := ButtonClick;
  Button2.OnClick := ButtonClick;
end;

procedure TForm1.ButtonClick(Sender: TObject);
begin
  if Sender is TButton then
  begin
    Caption := 'Button: ' + IntToStr(TButton(Sender).Tag);
  end;  
end;
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!