將 MainMenu 放入 ToolBar 後,系統會自動為選單項加入熱鍵(英文首字母底線、中文後綴 (Y)(Z)),導致開發者自訂的快捷鍵 (如 Ctrl+A、F1) 失效。即使設定 AutoHotkeys=maManual 也無效。本文整理兩位專家的解決方案:以自建 TPopupMenu 替換系統臨時選單,並配合 TActionList 實現真正的自訂快捷鍵。
運行時 TToolBar 並非直接使用設計時的 MainMenu,而是動態 new 一個 TPopupMenu,其 AutoHotkeys 預設為 maAutomatic,且無法從外部存取修改。此臨時選單會自動為項目添加熱鍵字元,覆蓋開發者設定的 ShortCut 屬性。
在表單建構函式中遍歷 ToolBar 按鈕,將 MenuItem 移至自建的 TPopupMenu 並設為 DropdownMenu:
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
for (int n = 0; n < ToolBar1->ButtonCount; n++) {
TToolButton *Btn = ToolBar1->Buttons[n];
if (Btn->DropdownMenu != NULL) {
Btn->MenuItem = NULL; // 已有 DropdownMenu,清除 MenuItem
} else if (Btn->MenuItem != NULL) {
TMenuItem *Item = Btn->MenuItem;
TPopupMenu *Menu = new TPopupMenu(this);
Menu->AutoHotkeys = maManual; // 關鍵:禁用自動熱鍵
Btn->DropdownMenu = Menu; // 替換為自建選單
// 同步原 MainMenu 的外觀屬性
if (Item->GetParentMenu()) {
Menu->BiDiMode = Item->GetParentMenu()->BiDiMode;
Menu->Images = Item->GetParentMenu()->Images;
}
Menu->HelpContext = Item->HelpContext;
Menu->TrackButton = tbLeftButton;
// 將原選單項目移至新選單 (逆序插入保持順序)
for (int i = Item->Count - 1; i >= 0; i--) {
TMenuItem *Item1 = Item->Items[i];
Item->Delete(i);
Menu->Items->Insert(0, Item1);
}
}
}
}
此法徹底移除系統自動熱鍵,但僅解決「不顯示多餘熱鍵」,原設定的 ShortCut 仍不生效(Ctrl+字母、F鍵 類型)。
TActionList 的 Action 可定義 ShortCut 並觸發 OnExecute。將選單項的 OnClick 邏輯轉移至對應 Action 的 OnExecute,並設定相同快捷鍵:
ActionList1,新增 Action (如 ActRedo)。ActRedo->ShortCut = Ctrl+R。RedoMenu->ShortCut = Ctrl+R (僅為顯示提示)。ActRedo->OnExecute 中呼叫 RedoMenu->Click();。void __fastcall TForm1::ActRedoExecute(TObject *Sender) {
RedoMenu->Click(); // 觸發原選單項邏輯
}
FormCreate 或建構函式執行方案一程式碼,移除系統自動熱鍵。Action,設定 ShortCut 並實作 OnExecute 呼叫對應選單項 Click()。ShortCut 顯示 (給使用者看),實際觸發由 Action 接管。Action 快捷鍵在表單焦點時全局響應,不受選單可見性影響。Action,選單項、工具列按鈕、快捷鍵共享同一實作。ActionList 編輯器直觀管理所有命令與快捷鍵。OnClick,可逐步遷移至 Action,新功能直接用 Action 開發。Action 的 ShortCut 優先級高於選單項,無衝突風險。結合「自建 TPopupMenu 禁用自動熱鍵」與「TActionList 接管快捷鍵觸發」,徹底解決工具列主選單自訂快捷鍵失效問題,賦予開發者完整的快捷鍵控制權。