狀態列 (CStatusBar) 分區 (Pane) 本質是矩形區域,非視窗。將 CProgressCtrl 建立為狀態列的子視窗,定位於特定分區矩形內,隨狀態列大小調整自動重新定位。
ID_INDICATOR_PROGRESS (值自動分配)。indicators[] 末尾加入此 ID,使進度條顯示在最右側。" "。
class CMainFrame : public CFrameWnd {
// ...
CProgressCtrl m_wndProgress; // 進度條控制項
BOOL m_bProgressCreated; // 是否已建立旗標
// ...
};
OnCreate 初始化
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;
// ... 建立工具列、狀態列 ...
m_bProgressCreated = FALSE;
return 0;
}
void CMainFrame::OnLongOperation() {
// 取得進度條分區矩形 (索引 4 視 indicators 陣列位置而定)
CRect rect;
m_wndStatusBar.GetItemRect(4, &rect); // 索引從 0 開始
if (!m_bProgressCreated) {
// 建立進度條,父視窗為狀態列
m_wndProgress.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH, rect, &m_wndStatusBar, 1);
m_wndProgress.SetRange(0, 100);
m_wndProgress.SetStep(1);
m_bProgressCreated = TRUE;
} else {
// 已存在,同步位置 (應對視窗大小變更)
m_wndProgress.MoveWindow(rect);
}
// 模擬長時間操作
for (int i = 0; i <= 100; ++i) {
m_wndProgress.StepIt();
Sleep(20); // 實際應在工作執行緒,並用 PostMessage 更新
// 處理訊息泵防止介面凍結
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
OnSize 中同步位置
void CMainFrame::OnSize(UINT nType, int cx, int cy) {
CFrameWnd::OnSize(nType, cx, cy);
if (m_bProgressCreated) {
CRect rect;
m_wndStatusBar.GetItemRect(4, &rect);
m_wndProgress.MoveWindow(rect); // 或 SetWindowPos
}
}
void CMainFrame::HideProgress() {
if (m_bProgressCreated) {
m_wndProgress.ShowWindow(SW_HIDE);
// 或完全銷毀:m_wndProgress.DestroyWindow(); m_bProgressCreated = FALSE;
}
}
UI 執行緒不應阻塞。工作執行緒計算進度,PostMessage 送自訂訊息 (WM_USER_PROGRESS) 到主框架,主框架 OnProgressUpdate 呼叫 m_wndProgress.SetPos。
| 樣式 | 效果 |
|---|---|
| PBS_SMOOTH | 平滑漸變 (Win98+),預設分段 |
| PBS_VERTICAL | 垂直進度條 |
| PBS_MARQUEE | 跑馬燈模式 (不確定進度),需 PBM_SETMARQUEE 啟動 |