如何知道 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 控件决定自己执行操作时才会自动重置。
我在 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'sExecute
method. After the action executes, the action resetsActionComponent
to nil (Delphi) or NULL (C++).
但是,ActionComponent
不会自动重置,只有在下一次 UI 控件决定自己执行操作时才会自动重置。