如何迭代TActionManager.ActionBars类中的每个TActionClientItem?

时间:2014-07-28 18:56:20

标签: delphi delphi-xe

问题

我喜欢使用TActionManager组件作为管理事件和使用TMainMenuTActionMainMenuBar构建菜单界面的更好方法,尽管我们会使用{{ 1}}因为TActionMainMenuBar中的ActionBars属性。

我遇到的一个令人讨厌的问题是图像索引有时会丢失,而且更常见的是它不会意味着必须通过每个TActionManager项并再次手动输入图像索引,如果要添加/删除则会很痛苦行动和图像等。

为了解决这个问题,我提出了迭代每个ActionBar并分配由其指定的TActionClientItem确定的图像索引的想法。

这是我到目前为止所提出的:

TAction

虽然这似乎有效,但它似乎不会处理子项。我想我需要某种递归程序,但我不知道如何实现它。根据我对递归的理解,它基本上意味着在一个过程中运行相同的过程?

使用一种方案重现丢失的TActionClientItem图像索引的步骤:

  • 创建一个新项目。
  • procedure TMyComponent.ReassignActionImages; var I, J, K: Integer; Manager: TActionManager; BarItem: TActionBarItem; Client: TActionClientItem; Action: TAction; begin for I := 0 to Owner.ComponentCount -1 do begin if (Owner.Components[I].ClassType = TActionManager) then begin Manager := TActionManager(Owner.Components[I]); for J := 0 to Manager.ActionBars.Count -1 do begin BarItem := Manager.ActionBars.ActionBars[J]; if BarItem.ActionBar <> nil then begin for K := 0 to BarItem.Items.Count -1 do begin Client := BarItem.Items[K]; if Client.Action <> nil then begin Action := TAction(Client.Action); if Action <> nil then begin Client.ImageIndex := Action.ImageIndex; //ShowMessage('Has Action: ' + Manager.Name + ' - ' + Action.Name + ' - ' + Client.Caption); end; end; end; end; end; end; end; end; 添加到表单。
  • TActionManager添加到TAction,将ImageIndex保留为-1。
  • TActionManager添加到表单。
  • 在表单设计器中选择TActionMainMenuBar,然后编辑TActionManager属性。
  • 添加新的ActionBars
  • 在对象检查器中将TActionBarItem指定为TActionMainMenuBar
  • 仍在对象检查器中,单击项目(ActionBar)属性。
  • 添加新的TActionClients,为其添加标题,例如&amp; File。
  • 再次点击项目(TActionClientItem)属性。
  • 添加新的TActionClients
  • 在Object Inspector中将TAction(例如,Action1)分配给TActionClientItem属性。
  • 在表单上放一个Action,然后添加一个位图。
  • 再次在表单设计器中选择TImageList,并将TActionManager分配给TImageList属性。
  • 双击Images,对于Action1,将ImageIndex更改为0
  • 运行应用程序,注意没有显示图像。
  • &amp; File菜单项也将被禁用,因此如果您愿意,只需编辑TActionManager的.OnExecute事件。
  • 再次运行,仍无图像显示。

上述方案的解决方案:

  • 要使图像可见,请编辑ActionBars并找到TAction手动将图像索引设置为0。
  • 运行应用程序,图像将显示。

以上是我可以重现的一个场景,它显示了如何更新TActionClientItem的图像索引以反映TAction中的更改。

还有其他时候发生这种情况(通常在添加,删除或修改TActionClientItem和图片时),需要手动更新TActions

这就是为什么我决定尝试制作一个简单的组件,以确保图像始终同步,并且无论TActionClientItem图像索引是否丢失或变得多余,如果它有{{{ 1}}已分配有图像索引我想将图像索引与TActionClientItem链接回来。

1 个答案:

答案 0 :(得分:2)

我实际上有点高兴,因为我曾经能够解决一个不那么明显的简单问题!

解决方法是在IterateClients上致电TActionManager.ActionBars,然后使用回调程序,我们就可以访问每个TActionClientItem

有用的文档链接:

http://docwiki.embarcadero.com/VCL/XE/en/ActnMan.TActionBars

http://docwiki.embarcadero.com/VCL/XE/en/ActnMan.TActionBars_Inherited_Members

http://docwiki.embarcadero.com/VCL/XE/en/ActnMan.TActionClientsCollection.IterateClients

在代码中,我设法做到了:

TMyComponent = class(TComponent)
protected
  procedure Loaded; override;
  procedure ActionCallBack(Client: TActionClient);
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
end;

procedure TMyComponent.Loaded;

  procedure SyncImages;
  var
    I: Integer;
    Manager: TActionManager;
  begin
    for I := 0 to Owner.ComponentCount -1 do
    begin
      if (Owner.Components[I].ClassType = TActionManager) then
      begin
        Manager := TActionManager(Owner.Components[I]);
        Manager.ActionBars.IterateClients(Manager.ActionBars, ActionCallBack);
      end;
    end;
  end;

begin
  inherited Loaded;
  SyncImages;
end;

{ ---------------------------------------------------------------------------- }

procedure TMyComponent.ActionCallBack(Client: TActionClient);
begin
  if (Client is TActionClientItem) then
  begin
    with TActionClientItem(Client) do
    begin
      if Action <> nil then
      begin
        Caption    := TAction(Action).Caption; // if you want to sync caption
        ImageIndex := TAction(Action).ImageIndex;
      end;
    end;
  end;
end;