我怎样才能看到谁在Delphi中触发了一个动作?

时间:2010-07-21 18:57:01

标签: delphi taction

当一个动作发射时,“发送者”始终是动作本身。通常这是最有用的,但是在某种程度上可以找出是谁触发了行动的onexecute事件?

示例

假设您有一张包含以下内容的表单:

  • 2个按钮,分别为Button1Button2
  • 1名称actDoStuff
  • 的TAction

为两个按钮分配了相同的操作。是否可以显示我点击了哪个按钮?

Example.dfm

object Form1: TForm1
  object Button1: TButton
    Action = actDoStuff
  end
  object Button2: TButton
    Action = actDoStuff
    Left = 100
  end
  object actDoStuff: TAction
    Caption = 'Do Stuff'
    OnExecute = actDoStuffExecute
  end
end

Example.pas

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);
  end;

var
  Form1: TForm1;

implementation    
{$R *.dfm}

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

end.

我目前看到的唯一解决方案是不使用按钮的action属性,而是为每个按钮设置一个事件处理程序,并从那里调用actDoStuffExecute(),但这种做法违背了在第一名。

我也不希望每个单独的控件都有专门的操作。上面的例子是我面临的问题的简化版本。我有一个菜单,其中包含可变数量的菜单项(文件名),除了加载另一个文件外,每个菜单项基本上都要做同样的事情。对每个菜单项执行操作会有点愚蠢。

7 个答案:

答案 0 :(得分:21)

尝试使用 ActionComponent 属性:

  

存储导致此操作执行的客户端组件。

     

使用 ActionComponent 来识别导致此操作执行的客户端组件。例如,如果您需要知道哪些用户操作触发了此操作,请从 OnExecute 事件处理程序中检查 ActionComponent

     

当用户点击客户端控件时,该客户端会在调用操作的 Execute 方法之前设置 ActionComponent 。执行操作后,操作会将 ActionComponent 重置为nil。

例如:

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

使用此功能,当我分别单击第一个和第二个按钮时,我会得到“Button1”和“Button2”。

答案 1 :(得分:9)

知道哪个按钮触发了操作类型与使用操作相反 - 可以通过按钮单击,菜单单击或任意数量的其他用户活动触发操作。存在用于统一启用/禁用的状态管理以及按钮和菜单之间的单击处理的操作。

如果你想知道哪个按钮触发了动作,因为你想要执行稍微不同的操作,或者以不同的方式“调整”操作,那么对于你想要做的事情,TAction可能不是正确的解决方案。

答案 2 :(得分:3)

而不是操作,只需使用点击事件。设置所有按钮以使用相同的事件处理程序。理想情况下,不是在第一个按钮后面命名(您可以重命名)。

以下是代码:

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;

答案 3 :(得分:1)

在某些情况下,相同的操作应适用于类似的控件。

的问题
ShowMessage( (Sender as TAction).ActionComponent.Name );

是当一个Say弹出菜单调用该动作时,您将获得弹出菜单的名称。你可以使用:

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;

答案 4 :(得分:1)

我有一堆面板,我想让用户右键单击这些面板中的任何一个,然后执行“删除文件”操作。 因此,我有一个与所有这些面板关联的弹出菜单。 这是我找出右键单击哪个面板的方法:

(注意:我发表了很多评论来清楚地解释它是如何工作的。但是,如果您不喜欢它,可以将代码压缩为两行(请参阅第二个过程)。)

因此,如果您已将操作分配给该弹出菜单:

procedure Tfrm.actDelExecute(Sender: TObject);
VAR
  PopMenu: TPopupMenu;
  MenuItem: TMenuItem;
  PopupComponent: TComponent;
begin
 { Find the menuitem associated to this action }
 MenuItem:= TAction(Sender).ActionComponent as TMenuItem;  { This will crash and burn if we call this from a pop-up menu, not from an action! But we always use actions, so.... }

 { Was this action called by keyboard shortcut? Note: in theory there should be no keyboard shortcuts for this action if the action can be applyed to multiple panels. We can call this action ONLY by selecting (right click) a panel! }
 if MenuItem = NIL then
  begin
   MsgError('This action should not be called by keyboard shortcuts!');
   EXIT;
  end;

 { Find to which pop-up menu this menuitem belongs to }
 PopMenu:= (MenuItem.GetParentMenu as TPopupMenu);

 { Find on which component the user right clicks }
 PopupComponent := PopMenu.PopupComponent;

 { Finally, access that component }
 (PopupComponent as TMonFrame).Delete(FALSE);
end;

如果您只有一个简单的弹出菜单(未分配操作):

procedure Tfrm.actDelHddExecute(Sender: TObject);
VAR PopupComponent: TComponent;
begin
 PopupComponent := ((Sender as TMenuItem).GetParentMenu as TPopupMenu).PopupComponent;
 (PopupComponent as TMonFrame).Delete(TRUE);
end;

您可以将所有代码放在一个返回TPanel的单个函数中,并像这样调用它:

procedure Tfrm.actDelWallExecute(Sender: TObject);
begin
 if GetPanelFromPopUp(Sender) <> NIL
 then GetPanelFromPopUp(Sender).Delete(FALSE);
end;

答案 5 :(得分:0)

好的,同时我觉得我找到了一个可行的解决方案..

我可以让所有控件使用相同的动作;我只需要覆盖他们的OnClick事件处理程序,我只需要一个处理器就可以使用它们。

我仍然有兴趣知道是否可以找出触发操作的控件,但对于我当前的应用程序,我使用的解决方案与下面的代码类似:

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.

答案 6 :(得分:0)

将按钮的标记设置为1,2,...等,然后:

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;