Вы находитесь на странице: 1из 3

Лекция 14 Таймер 1

ЛЕКЦИЯ 14
ТАЙМЕР ________________________________________________________________________________ 1
Создание таймера ______________________________________________________________________ 1
Остановка таймера _____________________________________________________________________ 1
Пример использования таймера___________________________________________________________ 2
Тестирование работы таймера ____________________________________________________________ 3

ТАЙМЕР

Создание таймера
Для создания системного таймера оконный класс может использовать функцию-член SetTimer ( )
класса CWnd со следующим прототипом:
UINT SetTimer ( UINT nIDEvent , UINT nElapse ,
void ( CALLBACK EXPORT* lpfnTimer ) (HWND , UINT , UINT , DWORD )) ;
Эта функция возвращает идентификатор таймера, если она выполнена успешно, и ноль противном
случае. Параметры:
nIDEvent идентификатор таймера;
nElapse задает время срабатывания таймера в миллисекундах;
lpfnTimer указатель на callback-функцию, которая обрабатывает сообщения WM_TIMER. Если
этот параметр равен NULL, сообщения WM_TIMER помещаются в очередь сообще-
ний приложения и обрабатываются оконным объектом.
По истечении времени в nElapse миллисекунд после установки таймера или предыдущего его сраба-
тывания система посылает сообщение WM_TIMER в очередь приложения или передает его для обра-
ботки функции, на которую указывает параметр IpfnTimer. Прототип функции, на которую ссылается этот
указатель, должен быть следующим:
void CALLBACK EXPORT
TimerProc ( HWND hWnd , UINT nMsg , UINT nIDEvent , DWORD dwTime ) ;
Здесь
hWnd дескриптор оконного объекта, который вызвал функцию SetTimer ( ),
nMsg идентификатор сообщения WM_TIMER,
nIDEvent идентификатор таймера;
dwTime системное время.
Имя этой функции не обязательно должно быть TimerProc, однако она должна возвращать 0.

Остановка таймера
Остановить установленный таймер можно с помощью функции-члена того же класса KillTimer ( ) со
следующим прототипом:
BOOL KillTimer ( int nIDEvent ) ;
В качестве параметра nIDEvent этой функции передается идентификатор таймера. Функция возвра-
щает TRUE, если таймер остановлен, и FALSE – если нет.
При размещении указанных функций в программе следует иметь в виду, что эти функции в конечном
итоге вызывают функции Windows, каким передается в качестве параметра дескриптор окна, с которым
связывается таймер. Это означает, что установка таймера не может быть произведена раньше, чем будет
создано окно. Наиболее ранней в смысле выполнения программы точкой для установки таймера является
обработчик события OnNcCreate ( ). Уничтожение таймера также должно производиться, когда окно еще
существует. Последней возможностью для вас в этом смысле является обработчик события
OnNcDestroy ( ) (но до вызова обработчика базового класса). Мы рекомендуем вам всегда делать это не-
сколько раньше – в обработчике события OnClose ( ) или OnDestroy ( ).
Обработчик событий таймера называется OnTimer ( ) и имеет прототип:
afx_msg void OnTimer (UINT nIDEvent ) ;
Его единственный параметр nIDEvent задает идентификатор таймера. Эта функция вызывается опе-
рационной системой, чтобы позволить вашему приложению обработать сообщение Windows
WM_TIMER. Параметр, передаваемый функции, отражает значение. которое он имел в момент получе-
ния его функцией окна приложения. Если вы вызовете в этом обработчике обработчик базового класса,

Выжол Ю.А. Программирование на Visual C++


Лекция 14 Таймер 2
этот последний будет использовать значение параметра, которое он имел в момент посылки сообщения
WM_TIMER, а не значение, переданное вами.

Пример использования таймера


Рассмотрим пример, который не только демонстрирует основные приёмы использования таймера, но
и позволяет тестировать его работу. Диалоговое окно IDD_TIMER_DIALOG содержит три таймера. Пер-
вый и второй таймер создаются после щелчка на кнопке “Включить”. Время срабатывания каждого
таймера пользователь может установить в соответствующих текстовых полях. Каждый таймер увеличива-
ет значение соответствующего счётчика, которые также отображаются в текстовых полях. Второй таймер
срабатывает реже, но увеличивает значение своего счётчика на большее значение. В среднем значения
обоих счётчиков должны быть равны. Оба таймера останавливаются при щелчке на кнопке “Выключить”.
Третий таймер включается при инициализации окна, срабатывает каждую секунду, отображает сис-
темное время и останавливается при закрытии окна.
Код, включённый в класс CTimerDlg, имеет вид:
class CTimerDlg : public CDialog
{
public :
int m_count1 ; // переменная, ассоциированная с текстовым полем IDC_COUNT1
int m_count2 ; // переменная, ассоциированная с текстовым полем IDC_COUNT2
CString m_time ; // переменная, ассоциированная с текстовым полем IDC_TIME
int m_elapse1 ; // время срабатывания первого таймера
int m_elapse2 ; // время срабатывания второго таймера
};
// функция обработки инициализации диалогового окна
BOOL CTimerDlg :: OnInitDialog ( )
{
CDialog :: OnInitDialog ( ) ;
•••
SetDlgItemInt ( IDC_ELAPSE1 , 100 ) ;
SetDlgItemInt ( IDC_ELAPSE2 , 1000) ; // определяет значения текстовых полей по умолчанию
SetTimer ( 3 , 1000 , NULL ) ; // создаёт третий системный таймер
return TRUE ;
}
// функция обработки щелчка на кнопке IDC_ON ("Включить")
void CTimerDlg :: OnOn ( )
{
m_elapse1 = GetDlgItemInt ( IDC_ELAPSE1 ) ;
m_elapse2 = GetDlgItemInt ( IDC_ELAPSE2 ) ;
// считывает данные из текстовых полей IDC_ELAPSE1 IDC_ELAPSE2
// в переменные m_elapse1 и m_elapse2
SetTimer ( 1 , m_elapse1 , NULL ) ; // создаёт первый системный таймер
SetTimer ( 2 , m_elapse2 , NULL ) ; // создаёт второй системный таймер
}
// функция обработки щелчка на кнопке IDC_OFF ("Выключить")
void CTimerDlg :: OnOff ( )
{
KillTimer ( 1 ) ; // останавливает первый системный таймер
KillTimer ( 2 ) ; // останавливает второй системный таймер
}
// функция обработки щелчка на кнопке IDC_OFF ("Выключить")
void CTimerDlg :: OnTimer ( UINT nIDEvent )
{
CTime curTime = CTime::GetCurrentTime ( ) ;
// создаёт переменную типа CTime и инициализирует её текущим системным временем
switch ( nIDEvent )
{
case 1: m_count1++; break; // наращивает первый счётчик
case 2: m_count2 += m_elapse2 / m_elapse1 ; break ; // наращивает второй счётчик
case 3: m_time = curTime.Format ("%d-%m-%y %H:%M:%S") ;

Выжол Ю.А. Программирование на Visual C++


Лекция 14 Таймер 3
// формирует строку с текущим системным временем
}
UpdateData ( false ) ; // считывает данные
// из ассоциированных переменных m_count1, m_count2 и m_time
// текстовые поля IDC_COUNT1, IDC_COUNT2 и IDC_TIME
CDialog :: OnTimer ( nIDEvent ) ;
}
// функция обработки закрытия диалогового окна
void CTimerDlg :: OnClose ( )
{
KillTimer ( 3 ) ; // останавливает третий системный таймер
CDialog :: OnClose ( ) ;
}

Тестирование работы таймера

Вид диалогового окна после 100 секунд работы показан на рисунке. Нетрудно видеть, что значения
счётчиков лишь приблизительно соответствуют системному времени.
Если мы уменьшим интервал срабатывания таймеров, то разница будет ещё больше. Несмотря на то,
что время срабатывания первого таймера установлено равным 1 мс, его реальное значение составило
16 мс.

Такое расхождение связано с тем, что операционная система посылает сообщение WM_TIMER в
очередь приложения и эта очередь не может продвигаться быстрее, чем происходит опрос внешних уст-
ройств.

Выжол Ю.А. Программирование на Visual C++

Вам также может понравиться