舊代碼使用 ::SendMessage(m_progress.GetSafeHwnd(), PBM_SETBARCOLOR, 0, RGB(255,0,255)) 設定進度條顏色,但在啟用 Visual Styles (XP 以上) 時無效。現代 MFC 應採用 自繪 (Owner Draw) 方式,完整掌控進度條外觀。
InitCommonControlsEx 或 Manifest 宣告 Visual Styles 後,系統使用主題繪製引擎,忽略 PBM_SETBARCOLOR。Owner Draw (資源編輯器勾選 Owner Draw Fixed 或代碼 ModifyStyle(0, PBS_OWNERDRAW))。WM_DRAWITEM 訊息 (或 OnDrawItem)。OnDrawItem 中繪製背景、進度塊、文字。void CMyDialog::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) {
if (nIDCtl != IDC_PROGRESS1) {
CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
return;
}
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;
int progress = m_progress.GetPos(); // 0-100
int max = 100; // 或 GetRangeMax()
// 1. 繪製背景
pDC->FillSolidRect(rect, RGB(240, 240, 240));
pDC->Draw3dRect(rect, RGB(180,180,180), RGB(255,255,255));
// 2. 計算進度區域
CRect barRect = rect;
barRect.DeflateRect(2, 2); // 內縮邊框
barRect.right = barRect.left + (barRect.Width() * progress / max);
// 3. 繪製漸層進度條 (自訂顏色)
COLORREF startColor = RGB(0, 120, 215); // 藍
COLORREF endColor = RGB(0, 80, 180);
for (int x = barRect.left; x < barRect.right; x++) {
double ratio = (double)(x - barRect.left) / barRect.Width();
int r = (int)(GetRValue(startColor) + ratio * (GetRValue(endColor) - GetRValue(startColor)));
int g = (int)(GetGValue(startColor) + ratio * (GetGValue(endColor) - GetGValue(startColor)));
int b = (int)(GetBValue(startColor) + ratio * (GetBValue(endColor) - GetBValue(startColor)));
pDC->FillSolidRect(x, barRect.top, 1, barRect.Height(), RGB(r,g,b));
}
// 4. 繪製百分比文字
CString str;
str.Format(_T("%d%%"), progress);
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(0,0,0));
pDC->DrawText(str, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
CMemDC 減少閃爍。IsAppThemed() 判斷是否啟用主題,決定是否自繪。OnTimer 中漸變 progress 並 Invalidate()。放棄 PBM_SETBARCOLOR,改用 PBS_OWNERDRAW + OnDrawItem,不僅相容所有 Windows 版本,還能實現漸層、圓角、動畫等豐富視覺效果。