在開發 MFC 應用程式時,常會遇到列表方塊(CListBox)項目文字過長、超出控件寬度的情況。若要在滑鼠指向該項目時顯示完整文字,類似工具列(Toolbar)的提示視窗是理想選擇。本文介紹一個可重用的 CPopupText 類別,繼承自 CWnd,能輕鬆實現淺黃底、黑字的彈出式提示視窗,不僅適用於列表方塊,也能擴展至組合框、列表視圖等通用控件。
CPopupText 封裝了提示視窗的建立、顯示、定位與自動尺寸計算。使用步驟如下:
CPopupText wndText;
wndText.Create(pParentWnd, WS_POPUP | WS_BORDER, 0, ptPos); // 先建立不可見視窗
wndText.SetWindowText(_T("完整的提示文字內容"));
wndText.ShowWindow(SW_SHOWNA); // SW_SHOWNA 避免搶奪焦點
類別會根據文字長度自動調整視窗大小,預設字體採用系統狀態列字體(NONCLIENTMETRICS::lfStatusFont)。關鍵在於使用 SW_SHOWNA 而非 SW_SHOW,確保提示視窗不成為作用中視窗,避免對話框標題列變灰。
ShowDelayed(UINT nDelayMs):設定毫秒級延遲顯示,nDelayMs=0 立即顯示,可替代 ShowWindow。Cancel():隱藏提示視窗或取消待執行的延遲顯示。為了自動處理列表方塊的項目寬度檢測與提示觸發,作者提供了 CListBoxTipHandler 類別,繼承自 CSubclassWnd(子類化輔助類別)。只需在對話框初始化時呼叫:
class CMyDialog : public CDialog {
CListBox m_wndList;
CListBoxTipHandler m_tipHandler;
// ...
BOOL OnInitDialog() {
// ...
m_tipHandler.Init(&m_wndList);
// ...
}
};
CListBoxTipHandler 會子類化目標列表方塊,攔截 WM_MOUSEMOVE 訊息,判斷滑鼠指向項目的文字寬度是否超過列表方塊客戶區寬度,決定是否啟動 CPopupText。兩大關鍵技巧:
SetCapture/ReleaseCapture 確保能收到最後一則滑鼠移動訊息,從而正確隱藏提示。SetWindowPos(..., SWP_NOACTIVATE) 及 ShowWindow(SW_SHOWNA),確保提示視窗不搶焦點、不干擾主視窗狀態。CListBoxTipHandler 提供兩個虛擬函數供覆寫,支援 Owner-draw 列表方塊及其他類列表控件:
OnGetItemInfo:取得指定項目的文字與矩形區域。IsRectCompletelyVisible:判斷項目矩形是否完整可見。注意:樹狀控件(Tree Control)內建 ToolTip 功能,無需此類別。
完整原始碼與範例程式(LCTest)可參考附件,快速為專案加入專業級的文字提示體驗。