大規模なレガシー アプリケーションのTMainMenu
階層をTActionMainMenuBar
アイテムにマップするクラスを作成しています。
最も重要な方法は、Steve Trevethen による EDN CodeCentralC の記事を大いに参考にしたもので、次のようになります。長々と申し訳ありませんが、これはおそらく、この場合に意味のあるコードを表示できる最短の長さです。
procedure TMainMenuSkin.DoLoadMenu(
ActionList: TCustomActionList;
Clients: TActionClients;
AMenu: TMenuItem;
SetActionList: Boolean = True;
bRecurseFlag:Boolean = False);
var
I: Integer;
J: Integer;
AC: TActionClientItem;
ca : TCustomAction;
newAction : TSkinnedMenuAction;
aci:TActionClientItem;
submenuitem : TMEnuItem;
procedure PopulateNodeFromMenuItem(menuitem:TMenuItem);
begin
newAction := TSkinnedMenuAction.Create(Application.MainForm);
menuitem.FreeNotification(newAction);
newAction.FMenuItem := menuitem;
newAction.Name := 'action_'+newAction.FMenuItem.Name;
FNewMenuActions.Add(newAction);
newAction.ActionList := ActionManager;
newAction.Tag := menuitem.Tag;
ca := newAction;
ca.ImageIndex := menuitem.ImageIndex;
ca.HelpContext := menuitem.HelpContext;
ca.Visible := menuitem.Visible;
ca.Checked := menuitem.Checked;
ca.Caption := menuitem.Caption;
ca.ShortCut := menuitem.ShortCut;
ca.Enabled := menuitem.Enabled;
ca.AutoCheck := menuitem.AutoCheck;
ca.Checked := menuitem.Checked;
ca.GroupIndex := menuitem.GroupIndex;
AC.ImageIndex := menuitem.ImageIndex;
AC.ShortCut := menuitem.ShortCut;
AC.Action := newAction;
end;
begin
if not Assigned(AMenu) then
exit;
AMenu.RethinkHotkeys;
AMenu.RethinkLines;
Clients.AutoHotKeys := False;
for I := 0 to AMenu.Count - 1 do
begin
AC := Clients.Add;
AC.Caption := AMenu.Items[I].Caption;
// Assign the Tag property to the TMenuItem for reference
AC.Tag := Integer(AMenu.Items[I]);
AC.Action := TContainedAction(AMenu.Items[I].Action);
AC.Visible := AMenu.Items[I].Visible;
// original sample code only created placeholders for submenus. I want to populate
// fully because I need the actions and their keyboard shortcuts to exist.
submenuitem := AMenu.Items[I];
if submenuitem.Count > 0 then
begin
if not bRecurseFlag then
AC.Items.Add // old busted way to work
else
begin
// How do I recursively populate the Action Clients menu?
DoLoadMenu(ActionList, AC.ActionClients, submenuitem, true);
end;
end
else
if ((AMenu.Items[I].Caption <> '') and (AMenu.Items[I].Action = nil) and
(AMenu.Items[I].Caption <> '-')) then
begin
PopulateNodeFromMenuItem( AMenu.Items[I] );
end;
AC.Caption := AMenu.Items[I].Caption;
AC.ImageIndex := AMenu.Items[I].ImageIndex;
AC.HelpContext := AMenu.Items[I].HelpContext;
AC.ShortCut := AMenu.Items[I].ShortCut;
AC.Visible := AMenu.Items[I].Visible;
end;
end;
上記の最も重要な行は次の行であり、間違っている行でもあります。
DoLoadMenu(ActionList, AC.ActionClients, submenuitem, true);
コードがそのように記述されている場合、すべてのメニュー項目がフラットな形式で表示されます。したがってAC.GetMeSubItems.ActionClients
、上記の行のようなものが必要ですが、それが何であるかわかりません。AC
タイプTActionClientItem
であり、実行時に作成されるツールバー ボタン自体です。
私の人生で理解できないのは、アクションリストとメニュー項目を一度に再帰的に入力する必要がある場合、どうすればよいですか? おそらく、私の考えは、ここで始めたサンプル コードによって制限されているのでしょう。これを行う方法を知るには、1行のコードしかないようです。
ここでいじっているさまざまなクラスの複雑な階層関係をよく理解していないように感じます。
更新: 次のように動作するようですが、私は自分自身を信頼していません。
aci := AC.Items.Add;
DoLoadMenu(ActionList, aci.Items, submenuitem, true);