Windows定时器使用方法

本文介绍MFC环境下定时器的使用方法,包括初始化、设置、处理及销毁过程。通过两个示例展示如何使用定时器更新UI上的计数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

范围

本文只讨论MFC环境下使用定时器的例子,用纯Win32 SDK是类似的。

主要思想

定时器的属性:

  • ID:每个定时器有个ID(UINT类型)。一个程序或窗体(如对话框)可以有多个定时器对象,每个定时器用ID区分。
  • Elapse:定时器的超时时间,单位是ms。
  • 回调函数(TimerProc):可以在SetTimer的时候直接指定定时器的回调函数。但在MFC方式下,使用WM_TIMER消息较为方便。

处理流程:

  • 初始化定时器的ID和Elapse;
  • SetTimer()创建定时器。之后,每隔Elapse的时间,都会触发WM_TIMER消息。
  • WM_TIMER消息处理:在Elapse间隔时间到的时候,do something.
  • KillTimer(): 当不再用定时器的时候,调用这个函数销毁定时器。

示例一(TimerTest)

一个简单的MFC对话框程序,两个按钮(Start&Stop),分别表示启动定时器和销毁定时器。每隔1秒钟更新一个整数值,并显示在UI上面。

成员变量

private:
    DWORD m_dwCount;
    UINT m_nTimerID;
    UINT m_nElapse;

消息处理函数的声明

public:
    afx_msg void OnBnClickedStart();
    afx_msg void OnBnClickedStop();
    afx_msg void OnTimer(UINT_PTR nIDEvent);

对话框资源

IDD_TIMERTEST_DIALOG DIALOGEX 0, 0, 233, 95
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "TimerTest"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    PUSHBUTTON      "Start",IDC_START,32,24,78,18
    PUSHBUTTON      "Stop",IDC_STOP,140,23,71,17
    EDITTEXT        IDC_COUNT,34,62,174,19,ES_AUTOHSCROLL
END

Message Map

删除了其他自动生成的代码,仅关注定时器相关:

BEGIN_MESSAGE_MAP(CTimerTestDlg, CDialogEx)
    ON_BN_CLICKED(IDC_START, &CTimerTestDlg::OnBnClickedStart)
    ON_BN_CLICKED(IDC_STOP, &CTimerTestDlg::OnBnClickedStop)
    ON_WM_TIMER()
END_MESSAGE_MAP()

DDX

void CTimerTestDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_COUNT, m_dwCount);
}

初始化

BOOL CTimerTestDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 自动生成的部分略过...

    // TODO: Add extra initialization here
    m_dwCount = 0;
    UpdateData(FALSE);

    m_nTimerID = 1;
    m_nElapse = 1000;
    GetDlgItem(IDC_START)->EnableWindow(TRUE);
    GetDlgItem(IDC_STOP)->EnableWindow(FALSE);

    return TRUE;
}

按钮事件&定时器消息处理

因为这个示例只有一个定时器,所以在OnTimer()用了一个assert。通常情况下,不需要这么做,参见下一个示例。

void CTimerTestDlg::OnBnClickedStart()
{
    SetTimer(m_nTimerID, m_nElapse, NULL);

    GetDlgItem(IDC_START)->EnableWindow(FALSE);
    GetDlgItem(IDC_STOP)->EnableWindow(TRUE);
}


void CTimerTestDlg::OnBnClickedStop()
{
    KillTimer(m_nTimerID);

    GetDlgItem(IDC_START)->EnableWindow(TRUE);
    GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
}


void CTimerTestDlg::OnTimer(UINT_PTR nIDEvent)
{
    assert(nIDEvent == m_nTimerID);

    m_dwCount++;
    UpdateData(FALSE);

    const DWORD MAX_COUNT = 100;
    if (m_dwCount == MAX_COUNT) {
        OnBnClickedStop();
    }
    CDialogEx::OnTimer(nIDEvent);
}

示例二(TimerTest2)

上面的例子,用了一个定时器。现在用2个定时器,以说明多个定时器的处理情况。

直接在上面的例子基础上修改,上面是显示一个整数,现在显示两个,对应两个Edit控件,一个称为Fast,另一个为Slow。前者定时器时长是1s,后者是2s。

资源文件

IDD_TIMERTEST_DIALOG DIALOGEX 0, 0, 233, 101
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "TimerTest"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    PUSHBUTTON      "Start",IDC_START,32,24,69,18
    PUSHBUTTON      "Stop",IDC_STOP,140,23,71,17
    LTEXT           "Fast",IDC_STATIC,30,52,63,13
    EDITTEXT        IDC_FAST,29,67,68,19,ES_AUTOHSCROLL
    LTEXT           "Slow",IDC_STATIC,136,51,63,13
    EDITTEXT        IDC_SLOW,135,66,68,19,ES_AUTOHSCROLL
END

.h文件

public:
    afx_msg void OnBnClickedStart();
    afx_msg void OnBnClickedStop();
    afx_msg void OnTimer(UINT_PTR nIDEvent);

private:
    DWORD m_dwFast;
    DWORD m_dwSlow;
    UINT m_nFastTimerID;
    UINT m_nSlowTimerID;
    UINT m_nElapse;

.cpp文件

static const UINT FAST_TIMER_ID = 1;
static const UINT SLOW_TIMER_ID = 2;

BEGIN_MESSAGE_MAP(CTimerTestDlg, CDialogEx)
    // some codes were delete ...

    ON_BN_CLICKED(IDC_START, &CTimerTestDlg::OnBnClickedStart)
    ON_BN_CLICKED(IDC_STOP, &CTimerTestDlg::OnBnClickedStop)
    ON_WM_TIMER()
END_MESSAGE_MAP()

BOOL CTimerTestDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // ...

    // TODO: Add extra initialization here
    m_dwFast = m_dwSlow = 0;
    UpdateData(FALSE);

    m_nFastTimerID = FAST_TIMER_ID;
    m_nSlowTimerID = SLOW_TIMER_ID;

    m_nElapse = 1000;

    GetDlgItem(IDC_START)->EnableWindow(TRUE);
    GetDlgItem(IDC_STOP)->EnableWindow(FALSE);

    return TRUE;
}

void CTimerTestDlg::OnBnClickedStart()
{
    SetTimer(m_nFastTimerID, m_nElapse, NULL);
    SetTimer(m_nSlowTimerID, m_nElapse * 2, NULL);

    GetDlgItem(IDC_START)->EnableWindow(FALSE);
    GetDlgItem(IDC_STOP)->EnableWindow(TRUE);
}

void CTimerTestDlg::OnBnClickedStop()
{
    KillTimer(m_nFastTimerID);
    KillTimer(m_nSlowTimerID);

    GetDlgItem(IDC_START)->EnableWindow(TRUE);
    GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
}


void CTimerTestDlg::OnTimer(UINT_PTR nIDEvent)
{
    switch (nIDEvent) {
    case FAST_TIMER_ID:
        m_dwFast++;
        break;
    case SLOW_TIMER_ID:
        m_dwSlow++;
        break;
    default:
        assert(false);//Unreachable branch
    }

    const DWORD MAX_COUNT = 100;
    if ((m_dwFast == MAX_COUNT) || (m_dwSlow == MAX_COUNT)) {
        OnBnClickedStop();
    }

    UpdateData(FALSE);

    CDialogEx::OnTimer(nIDEvent);
}

附件

附件是VS2010下的示例代码。

http://download.youkuaiyun.com/detail/u013344915/9417309

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值