关于MFC计时器的笔记

时间:2022-03-01 20:35:54

一、设置计时器

SetTimer:

函数原型:

UINT_PTR SetTimer( 
UINT_PTR nIDEvent,//计时器标识符
UINT nElapse,//超时间隔,每nElapse毫秒发送一次WM_TIMER消息
void (CALLBACK* lpfnTimer //指定WM_TIMER消息的回调,在本例中此函数为NULL,让默认OnTimer来处理计时器消息
)(HWND,
UINT,
UINT_PTR,
DWORD
)
);

销毁计时器 :

BOOL KillTimer(
UINT_PTR nIDEvent
);

或:

BOOL WINAPI KillTimer(
_In_opt_ HWND     hWnd,//响应计时器的窗口句柄
_In_     UINT_PTR uIDEvent//计时器ID
);
第一个为MFC封装后的KillTimer.第二个为WINAPI函数

在使用第二个WINAPI函数 KillTimer需指定设置计时器的窗口.如:

::KillTimer(hMyWnd,EVENT_TIMER_ID);

在不同窗口类之间传递计时器消息时注意事项:

如果指定窗口为空,则会抛出异常.

示例代码:

首选,建立一个对话框工程,工程名为 MyTimer,主对话框类为 CMyTimerDlg再添加一个对话框资源,创建类 CMyChildTimerDlg


在子窗口中创建计时器:

//mychildtimerdlg.cpp
BEGIN_MESSAGE_MAP(CMyChildTimerDlg, CDialogEx)
ON_WM_TIMER()
END_MESSAGE_MAP()

BOOL CMyChildTimerDlg::OnInitDialog()
{
//创建计时器
SetTimer(EVENT_ON_TIMER, 1000, NULL);//假设已全局定义#define EVENT_ON_TIMER 2
CDialogEx::OnInitDialog();
}
//OnTimer 计时器消息
void CMyChildTimerDlg::OnTimer(UINT_PTR nIDEvent)
{//响应计时器,发送消息给父窗口
::PostMessage(GetParent()->GetSafeHwnd(),
ON_WM_MYTIMER, (WPARAM)this, 0);

CDialogEx::OnTimer(nIDEvent);
}

在父窗口中响应计时器发来的消息:

头文件中:

//mytimerdlg.h
#include "MyChildTimerDlg.h"

public:
CMyChildTimerDlg* ChildTimer;
afx_msg LRESULT OnChildTimer(WPARAM wParam, LPARAM lParam);

实现文件:
//mytimerdlg.cpp

BEGIN_MESSAGE_MAP(CMyTimerDlg, CDialogEx)
ON_MESSAGE(ON_WM_MYTIMER,&CMyTimerDlg::OnChildTimer)//假设已定义消息ON_WM_MYTIMER
END_MESSAGE_MAP()

LRESULT CMyTimerDlg::OnChildTimer(WPARAM wParam, LPARAM lParam)
{
CMyChildTimerDlg* childTimer = (CMyChildTimerDlg*)wParam;
CMyChildTimerDlg* childTimer2 = (CMyChildTimerDlg*)lParam;//Error,Window is NULL

childTimer->KillTimer(EVENT_ON_TIMER);//OK,Timer will Kill;
childTimer2->KillTimer(EVENT_ON_TIMER);//Error, WINDOW is NULL;
}

当程序运行至 
chileTimer2->KillTimer(EVENT_ON_TIMER);

出错,

关于MFC计时器的笔记

然后我们调试代码.当代码运行至childTimer2->KillTimer(EVENT_ON_TIMER)时,抛出异常:

关于MFC计时器的笔记

中断程序,查看抛出异常的代码:

//afxwin2.inl

_AFXWIN_INLINE BOOL CWnd::KillTimer(UINT_PTR nIDEvent)
{ ASSERT(::IsWindow(m_hWnd)); return ::KillTimer(m_hWnd, nIDEvent); }

这里有一处断言,判断当前窗口是否存在.很时显,我们传过来的lParam是0,当然,窗口也就是NULL了.

另外,如果使用WIN API函数 ::KillTimer,虽然窗口为NULL不会抛出异常,但是相应的计时器也无法删除.