问题
我喜欢使用TActionManager
组件作为管理事件和使用TMainMenu
或TActionMainMenuBar
构建菜单界面的更好方法,尽管我们会使用{{ 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
。TActionClientItem
属性。Action
,然后添加一个位图。TImageList
,并将TActionManager
分配给TImageList
属性。Images
,对于Action1,将ImageIndex更改为0 TActionManager
的.OnExecute事件。上述方案的解决方案:
TAction
手动将图像索引设置为0。以上是我可以重现的一个场景,它显示了如何更新TActionClientItem
的图像索引以反映TAction
中的更改。
还有其他时候发生这种情况(通常在添加,删除或修改TActionClientItem
和图片时),需要手动更新TActions
。
这就是为什么我决定尝试制作一个简单的组件,以确保图像始终同步,并且无论TActionClientItem
图像索引是否丢失或变得多余,如果它有{{{ 1}}已分配有图像索引我想将图像索引与TActionClientItem
链接回来。
答案 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;