Хотя таймер и не оперирует такими понятиями, как потоки, среда, создаваемая с помощью сообщений WM_TIMER, весьма напоминает многозадачную среду.

Вся работа с таймером в MFC основана на двух методах: SetTimer и KillTimer класса CWnd.

UINT_PTR SetTimer
(
UINT_PTR nIDEvent,
UINT nELAPSE,
void (CALLBACK* lpfnTimer)
)

Метод, при успешном завершении возвращает номер создаваемого таймера. Первый параметр - номер создаваемого таймера. Второй параметр - количество миллисекунд, через которое срабатывает таймер. Третий параметр может быть либо равен NULL, либо указывать на некоторую функцию. В первом случае сообщение WM_TIMER посылает на функцию окна и, следовательно, обработчик должен быть включён в карту сообщений.
Если третий параметр отличен от NULL, то он должен указывать на некоторую функцию.

Вот её структура:

void CALLBACK EXPORT TimerProc
(
HWND hWnd,
UINT nMsg,
UINT nIDEvent,
DWORD dwTime
)
  • hWnd - дескриптор окна
  • nMsg - сообщение WM_TIMER
  • nIDEvent - индификатор таймера
  • dwTime - системное время

Уничтожить таймер можно с помощью метода KillTimer(UINT_PTR nIDEvent), аргументом которого является идентификатор таймера.

Следует заметить что точность таймера не слишком велика. При задержке сообщения в очереди новые сообщения таймера не накапливаются, а аннулируются.

Далее я приведу простую программу с двумя таймерами. Её смысл очень прост. В диалоговом окне имеется дополнительная кнопка, с помощью которой можно либо создать, либо уничтожить таймеры. Первый таймер каждую секунду формирует заголовок окна, увеличивая его длину на один символ. Второй таймер раз в 25 секунд очищает строку заголовка и посылает звуковой сигнал.

Вот файл Timer1Dlg.cpp:

#include "stdafx.h"
#include "Timer1.h"
#include "Timer1Dlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif



extern CTimer1Dlg * dlg;

void CALLBACK EXPORT OnTimer1(HWND, UINT, UINT, DWORD);

CTimer1Dlg::CTimer1Dlg(CWnd* pParent /*=NULL*/)
: CDialog(CTimer1Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_timer=0;
s="";
}

void CTimer1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BUTTON1, m_button);
}

BEGIN_MESSAGE_MAP(CTimer1Dlg, CDialog)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1)
ON_WM_TIMER()
END_MESSAGE_MAP()

BOOL CTimer1Dlg::OnInitDialog()
{
CDialog::OnInitDialog();

SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);

return TRUE;
}

void CTimer1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this);

SendMessage(WM_ICONERASEBKGND,
reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

HCURSOR CTimer1Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}

void CTimer1Dlg::OnBnClickedButton1()
{
if(!m_timer)
{
SetTimer(1,1000,NULL);
SetTimer(2,25000,OnTimer1);
m_button.SetWindowText("Удалить");
m_timer=1;
}else
{
KillTimer(1);
KillTimer(2);
m_button.SetWindowText("Таймеры");
m_timer=0;
}
}

void CTimer1Dlg::OnTimer(UINT nIDEvent)
{
CDialog::OnTimer(nIDEvent);
s=s+"*";
SetWindowText(s);
}

void CALLBACK EXPORT OnTimer1(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
dlg->s="";
dlg->SetWindowText(dlg->s);
::MessageBeep(0xFFFFFFFF);
}

Вот файл Timer1Dlg.h

#pragma once


class
CTimer1Dlg : public CDialog
{

public:
CTimer1Dlg(CWnd* pParent = NULL);

enum { IDD = IDD_TIMER1_DIALOG };


protected:
virtual void DoDataExchange(CDataExchange* pDX);



protected:
HICON m_hIcon;


virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CButton m_button;
int m_timer;
CString s;
afx_msg void OnBnClickedButton1();
afx_msg void OnTimer(UINT nIDEvent);
};

Файл Timer1.cpp:

#include "stdafx.h"
#include "Timer1.h"
#include "Timer1Dlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


CTimer1Dlg * dlg;

BEGIN_MESSAGE_MAP(CTimer1App, CWinApp)
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()


CTimer1App::CTimer1App()
{

}


CTimer1App theApp;


BOOL CTimer1App::InitInstance()
{

InitCommonControls();

CWinApp::InitInstance();


dlg = new CTimer1Dlg;
m_pMainWnd = dlg;
INT_PTR nResponse = dlg->DoModal();
if (nResponse == IDOK)
{

}
else if (nResponse == IDCANCEL)
{

}

return FALSE;
}

Модуль Timer1.cpp содержит запускающую часть проекта. Обратите внимание на способ задания диалогового окна. Объявление указателя на диалоговое окно позволяет упростить глобальный доступ из других модулей.

Читайте также:
  • Как с помощью COleDateTime узнать число предыдущего дня?
    Вариант1: с помощью COleDateTimeSpan - класс диапазона времени в днях: // Получаем текущее времяCOleDateTime t1 = COleDateTime::GetCurrentTime();// Выводим егоcout << "today : " ; cout << (LPCTSTR)t1.Format(_T("%A, %B %d, %Y")) << endl; COleDateTimeSpa...
  • Отображение текущего времени в панели CStatusBar
    Ниже приведён текст, описывающий создание MFC приложения, у которого в панели статуса отображается текущее время.Пять основных шагов: Используйте App Studio или Resource View в Visual C++ версий старше 4.0 для редактирования таблицы строк приложения. Добавьте новую строку в сегмент, объявленный к...
  • Эффективное копирование массивов
    Предположим, Вы хотите скопировать содержимое одного двумерного массива в другой: int weekly_hours[5][5]; // первый int another_array[5][5]; // второй Можно просто использовать вложенный цикл, чтобы скопировать каждый элемент weekly_hours в another_array, как показано в примере: for (int i =...
  • Получение числового значения символаПолучение числового значения символа
    Символ, заключённый в пару еденичных кавычек, представляет собой постоянное числовое значение, которое равно номеру символа в текущей раскладке символов (таких как ASCII, EBCDIC). Например: int n = 'A'; // n = 65 в системах, использующих ASCII Переменная n инициализирована числовым значени...
  • Как удалять динамически распределённый многомерный массив
    Распределить многомерный массив можно при помощи new следующим образом: class A{public: int j;//...конструктор, деструктор, и т.д.}void func(){ int m; A (*pa)[2][2]=new A[2][2][2]; // трёхмерный массив m=pa[0][0][0].j; // первый элемент массива m=pa[1][1][1].j; // последний элемент массива} Функци...