如何知道 TButton 单击是否执行了 TAction?

How to know if a TButton click executed a TAction?

我在 VCL 应用程序中使用 TActions 和 TButtons。将 TButtons Action 字段设置为现有操作可集中代码。

动作执行方法如下所示:

void __fastcall MyFrame::MyActionExecute(TObject *Sender)
{
//Some action code
}

将 MyAction 分配给名为 MyBtn 的 TButton 并查看操作 ActionComponent:

void __fastcall MyFrame::MyActionExecute(TObject *Sender)
{

  if(MyAction->ActionComponent == MyBtn)
  {
   //.. action code when the MyBtn was clicked..
  }
}

看起来效果不错。

但是,以编程方式调用 MyAction 的 Execute 方法,如下所示:

MyActionExcecute(NULL);

似乎没有将 ActionComponent 设置为 NULL,但 'still' 使用 MyBtn 作为 ActionCompoent。所以上面的 if 语句确实评估为真,即使没有点击按钮。

问题是,处理按钮点击和手动调用动作执行方法的正确方法是什么?

我知道我可以检查 Sender 参数是否为 NULL,如果是这样,我可以假设它不是按钮。

动作的 ActionComponent property is set only when a UI control is firing the action, via an internal TBasicActionLink object that the control creates internally for itself. The link's Execute() 方法有一个 AComponent 参数,控件将其 Self/this 指针传递给该参数,以在之前设置动作的 ActionComponent调用操作的 Execute() 方法。

例如,这是 VCL 内部所做的:

procedure TControl.SetAction(Value: TBasicAction);
begin
  if Value = nil then
  begin
    ActionLink.Free;
    ActionLink := nil;
    ...
  end
  else
  begin
    ...
    if ActionLink = nil then
      ActionLink := GetActionLinkClass.Create(Self);
    ActionLink.Action := Value;
    ...
  end;
end;
procedure TControl.Click;
begin
  { Call OnClick if assigned and not equal to associated action's OnExecute.
    If associated action's OnExecute assigned then call it, otherwise, call
    OnClick. }
  if Assigned(FOnClick) and (Action <> nil) and not DelegatesEqual(@FOnClick, @Action.OnExecute) then
    FOnClick(Self)
  else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
    ActionLink.Execute(Self) // <-- HERE
  else if Assigned(FOnClick) then
    FOnClick(Self);
end;
function TBasicActionLink.Execute(AComponent: TComponent): Boolean;
begin
  FAction.ActionComponent := AComponent; // <-- HERE
  Result := FAction.Execute;
end;

因此,不要直接调用您的 OnExecute 事件处理程序。那根本不会更新动作。改为调用操作的 Execute() 方法。您只需事先将操作的 ActionComponent 设置为 NULL,例如:

MyAction->ActionComponent = NULL;
MyAction->Execute();

documentation 声明:

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 (Delphi) or NULL (C++).

但是,ActionComponent 不会自动重置,只有在下一次 UI 控件决定自己执行操作时才会自动重置。