程式設計常需計時器,Windows 提供兩種實作方式:發送 WM_TIMER 訊息、呼叫應用程式定義的回呼函式。
UINT_PTR SetTimer(
HWND hWnd, // 視窗控制代碼
UINT_PTR nIDEvent, // 計時器 ID,多計時器時識別用
UINT uElapse, // 間隔毫秒數
TIMERPROC lpTimerFunc // 回呼函式,NULL 表示用 WM_TIMER
// 1 秒觸發一次
SetTimer(hWnd, 1, 1000, NULL);
// MFC 封裝 (CWnd::SetTimer)
UINT id = SetTimer(1, 100, NULL); // 100ms,回傳 ID
WM_TIMER 為低優先序訊息,訊息佇列擁塞時會延遲void CALLBACK TimerProc(
HWND hWnd, // 視窗控制代碼
UINT nMsg, // 訊息 (WM_TIMER)
UINT nTimerID, // 計時器 ID
DWORD dwTime); // 系統時間
SetTimer(1, 100, TimerProc); // 第三參數傳入回呼函式位址
安裝計時器時指定 ID,多計時器透過 ID 識別。
case WM_TIMER:
switch (wParam) // wParam 為計時器 ID
{
case 1: HandleTimer1(); break;
case 2: HandleTimer2(); break;
}
break;
void CTimerTestDlg::OnTimer(UINT nIDEvent)
{
switch (nIDEvent)
{
case 24: Draw1(); break; // ID 24 計時器
case 25: Draw2(); break; // ID 25 計時器
}
CDialog::OnTimer(nIDEvent);
}
void CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nTimerID, DWORD dwTime)
{
switch (nTimerID)
{
case 1: Do1(); break;
case 2: Do2(); break;
}
}
不再使用時必須呼叫 KillTimer 釋放資源。
BOOL KillTimer(
HWND hWnd, // 視窗控制代碼
UINT_PTR uIDEvent); // 計時器 ID
KillTimer(nIDEvent); // 直接傳入 ID
class CTimerDemoDlg : public CDialog
{
int m_nTimer1Count;
int m_nTimer2Count;
virtual BOOL OnInitDialog()
{
CDialog::OnInitDialog();
m_nTimer1Count = m_nTimer2Count = 0;
SetTimer(1, 1000, NULL); // 1 秒計時器
SetTimer(2, 500, NULL); // 0.5 秒計時器
return TRUE;
}
void OnTimer(UINT nIDEvent)
{
switch (nIDEvent)
{
case 1:
m_nTimer1Count++;
UpdateTimerDisplay(1, m_nTimer1Count);
if (m_nTimer1Count >= 10)
KillTimer(1); // 執行 10 次後停止
break;
case 2:
m_nTimer2Count++;
UpdateTimerDisplay(2, m_nTimer2Count);
break;
}
CDialog::OnTimer(nIDEvent);
}
};
| 技術 | 精度 | 適用場景 | 複雜度 |
|---|---|---|---|
| SetTimer/WM_TIMER | ~10-15ms | UI 更新、輪詢、動畫 | 低 |
| Multimedia Timer (timeSetEvent) | ~1ms | 音訊、遊戲迴路 | 中 |
| Waitable Timer (CreateWaitableTimer) | ~0.5ms | 執行緒同步、精確排程 | 中高 |
| High-Resolution Timer (QueryPerformanceCounter) | < 1μs | 效能分析、科學計算 | 高 |
| Timer Queue (CreateTimerQueueTimer) | ~1ms | 執行緒池排程、服務型應用 | 中高 |
SetTimer(NULL, 0, ...) 讓系統自動分配唯一 IDKillTimer → OnDestroy 中清理所有計時器QueryPerformanceCounter