首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

MFC SetTimer/OnTimer/KillTimer 實作倒數計時器:常見邏輯錯誤與修正

     編輯:程式設計疑難解答

原代碼問題分析

void CTimerDlg::OnTimer(UINT_PTR nIDEvent) {
    CDialogEx::OnTimer(nIDEvent);
    CString szTimeFormat;
    if (iSecond == -1) return;
    while (iSecond >= 0) {          // ❌ 錯誤:while 會阻塞 UI 執行緒,導致介面凍結
        szTimeFormat = ToTimeFormat(iSecond);
        SetDlgItemText(IDC_OUT, szTimeFormat);
    }
    iSecond--;                      // ❌ 在 while 結束後才遞減,邏輯倒置
}

核心錯誤

  1. while 迴圈阻塞訊息泵:OnTimer 在 UI 執行緒執行,while 會佔用整個執行緒,導致視窗無法重繪、無法響應按鈕、甚至系統判定「未回應」。
  2. 邏輯順序錯誤:應先顯示當前秒數,**然後**遞減,下一次 Timer 觸發時顯示新值。
  3. 未殺死 Timer:倒數結束時需呼叫 KillTimer。

正確實作

// 成員變數
int m_nRemainingSeconds = 0;
const UINT ID_TIMER_COUNTDOWN = 1;

void CTimerDlg::OnBnClickedBegin() {
    CString str;
    GetDlgItemText(IDC_IN, str);
    m_nRemainingSeconds = ToSecond(str);  // 解析輸入秒數
    SetDlgItemText(IDC_OUT, ToTimeFormat(m_nRemainingSeconds));
    SetTimer(ID_TIMER_COUNTDOWN, 1000, NULL);  // 1 秒觸發一次
}

void CTimerDlg::OnTimer(UINT_PTR nIDEvent) {
    if (nIDEvent != ID_TIMER_COUNTDOWN) {
        CDialogEx::OnTimer(nIDEvent);
        return;
    }
    
    if (m_nRemainingSeconds > 0) {
        m_nRemainingSeconds--;
        SetDlgItemText(IDC_OUT, ToTimeFormat(m_nRemainingSeconds));
    } else {
        // 倒數結束
        KillTimer(ID_TIMER_COUNTDOWN);
        MessageBox(_T("時間到!"), _T("提示"), MB_ICONINFORMATION);
    }
}

void CTimerDlg::OnBnClickedStop() {
    KillTimer(ID_TIMER_COUNTDOWN);
    m_nRemainingSeconds = 0;
    SetDlgItemText(IDC_OUT, _T("00:00:00"));
}

關鍵點總結

錯誤做法正確做法
while 迴圈在 OnTimer 內阻塞OnTimer **只做一次** 更新,依賴系統每秒回呼
遞減邏輯在迴圈外每次 OnTimer **先遞減/判斷,再顯示**
未處理倒數結束秒數歸零時 KillTimer + 提示
硬編碼 Timer ID定義 const UINT ID_TIMER = 1 避免衝突

進階:高精度/暫停/繼續

  • 需高精度(< 1 秒)可用 timeSetEvent (multimedia timer) 或 CreateTimerQueueTimer。
  • 暫停/繼續:KillTimer 保存剩餘秒數,繼續時 SetTimer 恢復。

總結

MFC 倒數計時器核心:**OnTimer 只執行單次更新**,靠系統週期性觸發。**切勿在 OnTimer 使用迴圈**,否則凍結 UI。正確流程:啟動 → SetTimer → OnTimer 遞減顯示 → 歸零 KillTimer。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved