MFC 預設僅在狀態列顯示選單提示 (離視線遠、易被忽略)。本文介紹 **CMenuTipManager** 類別,僅需一行代碼接入,即可在 **滑鼠懸停選單項 1 秒後,於項目右側彈出 ToolTip 顯示命令提示字串**,支援主選單、系統選單、右鍵選單,並解決右鍵選單無 WM_MENUSELECT 通知的難題 (WM_ENTERIDLE),附帶黏性顯示優化。
圖一:選單項右側精準彈出 ToolTip,字體/顏色模擬系統標準提示
// CMainFrame 成員 CMenuTipManager m_menuTipManager; // OnCreate 中 m_menuTipManager.Install(this); // 傳入主框架指標,內部子類化攔截訊息
CSubclassWnd 子類化主框架攔截訊息WM_MENUSELECT:用戶在選單中移動滑鼠/鍵盤導航時發送,攜帶選中項目 ID、旗標、父選單句柄。主選單/系統選單/右鍵選單統一發送。WM_ENTERIDLE:程式進入閒置等待輸入狀態時發送 (選單/對話框顯示中)。關鍵參數:lParam 為當前顯示的選單/對話框視窗句柄,用於偵測右鍵選單滑鼠離開 (無 WM_MENUSELECT 通知)。CPopupText (輕量級)Create)、設定文字 (SetWindowText)、延遲顯示 (ShowDelayed(ms))、取消 (Cancel)。SystemParametersInfo(SPI_GETNONCLIENTMETRICS) 取得選單字體;背景色用 GetSysColor(COLOR_INFOBK)。EnumWindows 列舉頂層視窗,匹配類別名 #32768 (選單類)。GetRunningMenuWnd() 返回當前活動選單 HWND (Z 序最上者)。GetWindowRect → 客戶區左上角為基準 → 遍歷選單項 (需解析選單結構或近似計算) 累加高度至目標項 → 計算 ToolTip 顯示座標 (項目右側對齊)。WM_ENTERIDLE 替代缺失的 WM_MENUSELECTvoid CMenuTipManager::OnEnterIdle(UINT nWhy, CWnd* pWnd)
{
if (nWhy == MSGF_MENU) // 選單模態中
{
HWND hMenuWnd = (HWND)lParam; // 隨 WM_ENTERIDLE 傳入的選單視窗句柄
HWND hWndUnderMouse = ::WindowFromPoint(GetCursorPos());
if (hWndUnderMouse != hMenuWnd && hWndUnderMouse != m_hwndTip)
{
// 滑鼠已離開選單視窗 (也非 Tip 視窗本身)
m_wndTip.Cancel(); // 隱藏提示
m_bSticky = FALSE; // 重置黏性
}
}
}
m_bSticky)ShowDelayed(1000))。m_bSticky = TRUE,後續切換項目 **立即顯示** (ShowDelayed(0)),無需等待。m_bSticky = FALSE。MFC 字串資源格式為 "長提示\n短提示"。若需支援禁用說明,擴展為 "長提示\n短提示\n禁用說明",修改 GetResCommandPrompt 解析第三段,在 OnGetCommandPrompt 中檢查 MF_DISABLED 旗標返回禁用說明。留作讀者練習。
CMenuTipManager 以 ~200 行代碼 實現了商業級選單 ToolTip 體驗:**零侵入式接入、全選單類型支援、智慧定位、右鍵選單離開偵測、黏性優化、系統視覺一致性**。源碼結構清晰,強烈建議整合至專案通用 UI 庫。