| 模式 | API | 觸發方式 | 精度/延遲 | 適用場景 |
|---|---|---|---|---|
| 消息隊列模式 | SetTimer(hWnd, id, elapse, NULL) | 發送 WM_TIMER 到消息隊列 | 低優先級,可能延遲 (~10-50ms) | UI 更新、非關鍵周期檢查 |
| 回調函數模式 | SetTimer(hWnd, id, elapse, TimerProc) | 直接調用回調函數 | 較低延遲,但需線程安全 | 高精度、非 UI 線程 |
CWnd::SetTimer / KillTimer
// 啟動定時器
UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD));
// 停止定時器
BOOL KillTimer(UINT_PTR nIDEvent);
nIDEvent:定時器 ID,同一窗口內唯一,用於 WM_TIMER 中區分。nElapse:間隔毫秒數 (最小 ~10-15ms,受系統時鐘分辨率限制)。lpfnTimer = NULL:使用消息隊列模式 (推薦 UI 線程)。
class CMyDlg : public CDialog {
// ...
void StartTimers() {
SetTimer(1, 500, NULL); // ID=1, 500ms
SetTimer(2, 1000, NULL); // ID=2, 1000ms
SetTimer(3, 2000, NULL); // ID=3, 2000ms
}
void StopTimers() {
KillTimer(1);
KillTimer(2);
KillTimer(3);
}
// WM_TIMER 處理器 (ClassWizard 添加)
void OnTimer(UINT_PTR nIDEvent) {
switch (nIDEvent) {
case 1: OnTimer500ms(); break;
case 2: OnTimer1s(); break;
case 3: OnTimer2s(); break;
}
CDialog::OnTimer(nIDEvent);
}
void OnTimer500ms() { /* 高頻檢查 */ }
void OnTimer1s() { /* 秒級更新 UI */ }
void OnTimer2s() { /* 低頻後台任務 */ }
};
if (SetTimer(1, 100, NULL) == 0) {
AfxMessageBox(_T("系統定時器資源耗盡!"));
}
WM_TIMER 低優先級特性WM_TIMER 會被延遲處理。WM_TIMER 可能合併 (若處理太慢),導致丟失觸發。timeSetEvent) 或高精度計時器 (QueryPerformanceCounter + 等待)。SetTimer
SetTimer(1, 500, NULL); // 500ms
// 後續動態改為 200ms
SetTimer(1, 200, NULL); // 修改現有定時器間隔
void CMyDlg::OnDestroy() {
KillTimer(1); KillTimer(2); KillTimer(3);
CDialog::OnDestroy();
}
void CScheduleView::OnTimer(UINT nIDEvent) {
if (nIDEvent != 1) return; // 僅處理 ID=1
CTime now = CTime::GetCurrentTime();
CTimeSpan tolerance(0, 0, 15, 0); // 15秒容差
CScheduleDoc* pDoc = GetDocument();
ScheduleItem* pUp = pDoc->m_pNearestTaskUp; // 最近已過期任務
ScheduleItem* pDown = pDoc->m_pNearestTaskDown; // 最近即將到來任務
// 檢查是否有任務狀態變化
bool needUpdate = false;
if (pUp && pUp->ti < now - tolerance) needUpdate = true;
if (pDown && pDown->ti <= now + tolerance) needUpdate = true;
if (needUpdate) {
pDoc->SearchNearestTask(); // 重新計算最近任務
pDoc->UpdateState(); // 更新任務狀態
pDoc->UpdateAllViews(NULL, 0, NULL); // 刷新視圖
}
// 即將到來提醒:彈窗並置頂
if (pDown && pDown->ti <= now + tolerance) {
AfxGetMainWnd()->ShowWindow(SW_RESTORE);
SetForegroundWindow();
CString msg = _T("提醒: \"") + pDown->des + _T("\" 即將開始!");
AfxMessageBox(msg);
}
}
#include
#pragma comment(lib, "winmm.lib")
MMRESULT timerId;
void CALLBACK TimeProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
// 高精度回調 (1ms 分辨率)
}
void StartHighResTimer() {
TIMECAPS tc; timeGetDevCaps(&tc, sizeof(tc));
timerId = timeSetEvent(1, tc.wPeriodMin, TimeProc, 0, TIME_PERIODIC);
}
void StopHighResTimer() {
timeKillEvent(timerId);
}
KillTimer → 定時器洩漏,資源耗盡。WM_TIMER 處理耗時過長 → 阻塞 UI 線程,導致消息堆積、定時器合併/丟失。SetTimer 返回 0 未檢查 → 靜默失效。VC 多定時器核心:SetTimer(id, interval, NULL) 啟動消息隊列模式、OnTimer(id) 分派處理、KillTimer(id) 清理。ID 區分多定時器,間隔單位毫秒。WM_TIMER 低優先級、非實時,嚴格場景用多媒體定時器。窗口銷毀必清理,返回值必檢查。掌握此模式,實現周期性 UI 更新、後台輪詢、排程提醒等功能得心應手。