工具提示 是現代 GUI 必備元素。MFC 透過 CToolTipCtrl 封裝,但 對話框架構 (CDialog) 與 框架視窗架構 (CFrameWnd) 的實現機制截然不同。本文系統闡述原理、兩種架構的標準實現流程、工具列/狀態列/標題列的提示添加技巧。
ToolTip 控制項需顯示文字時,發送 TTN_NEEDTEXT 通知訊息 (WM_NOTIFY) 給父視窗,父視窗在處理函數中填入 TOOLTIPTEXT::lpszText 即可。關鍵差異在於 訊息路由機制。
CDialog 未自動路由 TTN_NEEDTEXT,開發者必須自行加入訊息映射與處理函數。
EnableToolTips(TRUE); (在 OnInitDialog)。ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTip) (ID 固定為 0)。afx_msg BOOL OnToolTip(UINT id, NMHDR* pNMHDR, LRESULT* pResult);。BOOL CMyDialog::OnToolTip(UINT, NMHDR* pNMHDR, LRESULT*) {
TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR;
UINT nID = pNMHDR->idFrom; // 控制項 ID
// 若 idFrom 實為 HWND (TTF_IDISHWND),轉換為控制項 ID
if (pTTT->uFlags & TTF_IDISHWND)
nID = ::GetDlgCtrlID((HWND)nID);
if (nID == 0) return FALSE;
switch (nID) {
case IDOK: pTTT->lpszText = _T("確定按鈕"); break;
case IDCANCEL: pTTT->lpszText = _T("取消按鈕"); break;
// ... 其他控制項
}
return TRUE; // 表示已處理
}
CFrameWnd 內建預設處理器,可自動顯示工具列按鈕的提示 (來自資源字串表)。但為了支援自定義提示 (標題列、狀態列、非工具列控制項),需額外管理 CToolTipCtrl 成員。
CToolTipCtrl m_ToolTip;if (!m_ToolTip.Create(this, TTS_ALWAYSTIP)) return -1; // 非活動視窗也顯示
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) {
m_ToolTip.RelayEvent(pMsg); // 關鍵:轉發滑鼠/鍵盤訊息
return CFrameWnd::PreTranslateMessage(pMsg);
}
CString t; GetWindowText(t); m_ToolTip.AddTool(this, t);CBRS_TOOLTIPS | CBRS_FLYBY,MFC 自動從字串表 (ID 與按鈕 ID 相同) 讀取提示文字。m_ToolTip.AddTool(&m_wndStatusBar, _T("狀態列")); m_ToolTip.Activate(TRUE);資源字串表中,ID 與工具列按鈕命令 ID 相同,字串格式:狀態列文字\n工具提示文字。
例:ID ID_FILE_OPEN 字串 \"開啟現有文件\nOpen\" → 狀態列顯示「開啟現有文件」,ToolTip 顯示「Open」。
| 特性 | CDialog 對話框 | CFrameWnd 框架視窗 |
|---|---|---|
| TTN_NEEDTEXT 路由 | 無自動路由,需 ON_NOTIFY_EX 手動處理 | 有預設路由,自動處理工具列按鈕 | 通常不需要 (靠訊息處理) | 必須 (管理非工具列提示、轉發訊息) |
| PreTranslateMessage | 不需轉發 | 必須 RelayEvent |
| 提示文字來源 | 代碼中 switch-case 硬編碼/查表 | 工具列自動讀字串表;其他手動 AddTool |
理解架構差異,即可在任何 MFC 專案中正確、高效地實現工具提示。