MFC 標準菜單項的單選框(Radio)和復選框(Check)圖標由系統自動繪製,但在自繪菜單(Owner Draw)模式下,開發者需自行處理圖標繪製,常遇到圖標與文字對齊偏移、間距不一致等問題。
將圖標繪製納入自繪邏輯,在 `OnMeasureItem` 和 `OnDrawItem` 中統一處理:
void CMyMenu::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) {
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect(lpDrawItemStruct->rcItem);
// 1. 獲取菜單項狀態
UINT nState = GetMenuState(lpDrawItemStruct->itemID, MF_BYCOMMAND);
BOOL bChecked = (nState & MF_CHECKED) != 0;
BOOL bSelected = (lpDrawItemStruct->itemState & ODS_SELECTED) != 0;
// 2. 繪製背景
CBrush brush(bSelected ? GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_MENU));
pDC->FillRect(&rect, &brush);
// 3. 計算圖標區域(左側固定寬度)
CRect iconRect = rect;
iconRect.right = iconRect.left + 20; // 圖標區寬度
iconRect.DeflateRect(2, 2); // 內邊距微調
// 4. 繪製勾選/單選圖標
if (bChecked) {
// 方案 A:使用系統圖標
DrawFrameControl(pDC->m_hDC, &iconRect, DFC_MENU,
bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK);
// 方案 B:自定義圖標(更靈活控制位置)
// CBitmap bmp; bmp.LoadBitmap(IDB_CHECK);
// pDC->DrawState(iconRect.TopLeft(), iconRect.Size(), &bmp, DSS_NORMAL);
}
// 5. 繪製文字(右側區域)
CRect textRect = rect;
textRect.left = iconRect.right + 4; // 圖標與文字間距
CString strText;
GetMenuString(lpDrawItemStruct->itemID, strText, MF_BYCOMMAND);
pDC->DrawText(strText, &textRect, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
// 6. 繪製快捷鍵(右側對齊)
// ... 類似處理
}
| 參數 | 建議值 | 說明 |
|---|---|---|
| 圖標區寬度 | 20-24px | 包含圖標本體 + 左右內邊距 |
| 圖標垂直居中 | `iconRect.CenterPoint().y` | 計算項目中心 Y 座標對齊 |
| 文字左邊距 | `iconRect.right + 4~8px` | 保持統一視覺間距 |
| 高亮反色 | `COLOR_HIGHLIGHT` / `COLOR_HIGHLIGHTTEXT` | 系統主題適配 |
核心原則:統一座標計算體系,所有位置相對項目矩形計算,避免硬編碼。參考系統菜單測量邏輯(`GetSystemMetrics(SM_CYMENU)` 等)可獲得最佳視覺一致性。