【问题标题】:How to know if a TButton click executed a TAction?如何知道 TButton 点击​​是否执行了 TAction?
【发布时间】:2020-09-01 20:27:53
【问题描述】:

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

actions Execute 方法如下所示:

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,但“仍然”使用 MyBtn 作为 ActionCompoent。因此,即使未单击按钮,上面的 if 语句也会计算为 true。

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

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

【问题讨论】:

    标签: c++builder vcl


    【解决方案1】:

    动作的ActionComponent 属性仅在UI 控件触发动作时通过控件内部为自身创建的内部TBasicActionLink 对象设置。链接的Execute() 方法有一个AComponent 参数,控件将其Self/this 指针传递给该参数,以在调用操作的Execute() 方法之前设置操作的ActionComponent

    例如,这是 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 声称:

    当用户单击客户端控件时,该客户端会在调用操作的Execute 方法之前设置ActionComponent动作执行后,动作将ActionComponent 重置为 nil (Delphi) 或 NULL (C++)

    但是,ActionComponent 不会自动重置,仅当 UI 控件下一次决定为自己执行操作时。

    【讨论】:

    • 感谢您的出色回答。那么文档说 ActionComponent 在执行后设置为 NULL 是错误的和误导性的吗?
    • @TotteKarlsson 是的。在发布我的答案之前,我仔细检查了 VCL 源代码。执行操作后不会重置 ActionComponent
    猜你喜欢
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    相关资源
    最近更新 更多