О таймере

=== О таймере ===
Компонент timer (таймер) служит для отсчета интервалов реального времени. Его свойство interval определяет интервал временив миллисекундах , который должен пройти от включения таймера до наступления события ontimer. Таймер включается при установке значения true в его свойство enabled. Единожды включенный таймер все время будет возбуждать события ontimer до тех пор, пока его свойство enabled не примет значения false.
 
Следует учесть, что в силу специфики реализации стандартного аппаратного таймера ibm-совместимого компьютера минимальный реально достижимый интервал отсчета времени не может быть меньше 55 мс (этот интервал называется тиком), более того, любой интервал времени, отсчитываемый с помощью таймера, всегда кратен 55 мс. Чтобы убедиться в этом, проведите эксперимент, в котором подсчитывается среднее время между двумя срабатываниями таймера (timer.dpr):
Начните новый проект с пустой формой и положите на нее компонент TTimer. 
unit unit1; 
interface 
uses 
 windows, messages, sysutils, classes, graphics, controls, forms, 
 dialogs, stdctrls, buttons, extctrls; 
type 
 TfmExample = class(TForm) 
 Panel1: TPanel; 
 bbRun: TBitBtn; 
 bbClose: TBitBtn; 
 edInput: TEdit; 
 lbOutput: TLabel; 
 mmOutput: TMemo; 
 Timer1: TTimer; 
 procedure bbRunClick(Sender: TObject); 
 procedure Timer1Timer(Sender: TObject); 
 procedure FormActivate(Sender: TObject); 
 private 
 BegTime: TDateTime; // Начальное время цикла 
 Counter: Integer; // Счетчик цикла 
 end; 
var
 fmExample: TfmExample; 
implementation 
{$r *.dfm} 
// Запускает таймер. edinput содержит период его срабатывания. 
procedure TfmExample.bbRunClick(Sender: TObject); 
var delay: Word; 
begin 
 // Проверяем задание интервала 
 if edInput.Text= then Exit; 
 try 
 delay := StrToInt(edInput.Text); 
 except 
 ShowMessage('Ошибка в записи числа'); 
 edInput.SelectAll; 
 edInput.SetFocus; 
 Exit 
 end; 
 Counter := 0; // Сбрасываем счетчик 
 Timer1.Interval := delay; // Устанавливаем интервал 
 BegTime := Time; // Засекаем время 
 Timer1.Enabled := True; // Пускаем таймер 
 Screen.Cursor := crHourGlass; 
end; 
procedure TfmExample.Timer1Timer(Sender: TObject); 
 var h, m, s, ms: Word; // Переменные для декодирования времени 
 const maxCount = 55; // Количество срабатываний таймера 
begin 
 Counter := Counter + 1; // Наращиваем счетчик срабатываний 
 if Counter = maxCount then // Конец цикла? 
 begin // - Да 
 Timer1.Enabled := False; // Останавливаем таймер 
 // Находим среднее время срабатывания: 
 DecodeTime((Time-Begtime)/maxCount, h, m, s, ms); 
 // Выводим результат 
 mmOutput.Lines.Add(Format('Задано %s ms. Получено %d ms.', [edInput.Text, ms])); 
 edInput.Text := ; // Готовим следующий запуск 
 edInput.SetFocus; 
 Screen.Cursor := crDefault;
 end; 
end; 
procedure TfmExample.FormActivate(Sender: TObject); 
begin 
 edInput.SetFocus();
end; 
end. 
Необходимость нескольких (maxCount) срабатываний для точного усреднения результата связана с тем, что системные часы обновляются каждые 55 мс. После запуска программы и ввода 1 как требуемого периода срабатывания в редакторе mmoutput вы увидите строку 
Задано 1 ms. Получено 55 ms. 
в которой указывается, какое реальное время разделяет два соседних события OnTimer. Если вы установите период таймера в диапазоне от 56 до 110 мс, в строке будет указано 110 ms и т.д. (в силу дискретности обновления системных часов результаты могут несколько отличаться в ту или иную сторону). 
В ряде практически важных областей применения (при разработке игр, в системах реального времени для управления внешними устройствам и т.п.) интервал 55 мс может оказаться слишком велик. Современный ПК имеет мультимедийный таймер, период срабатывания которого может быть от 1 мс и выше, однако этот таймер не имеет компонентного воплощения, поэтому для доступа к нему приходится использовать функции api. 
Общая схема его использования такова. Сначала готовится процедура обратного вызова (call back) с заголовком: 
procedure timeProc(uid, umsg: uint; dwuser, dw1, dw2: dword); stdcall; 
Запуск таймера реализуется функцией: 
function timeSetEvent(udelay, uresolution: uint; lptimeproc: pointer; dwuser: dword; fuevent: uint): uint; stdcall; external 'winmm.dll'; 
Таймер останавливается, и связанные с ним системные ресурсы освобождаются функцией: 
function timeKillEvent(uid: uint): uint; stdcall; external 'winmm.dll'; 
Здесь uid - идентификатор события таймера, полученный с помощью timesetevent. 
В следующем примере (timer.dpr) иллюстрируется использование мультимедийного таймера (листинг 5).
unit unit1; 
interface 
uses 
 windows, messages, sysutils, classes, graphics, controls, forms, 
 dialogs, stdctrls, buttons, extctrls; 
type 
 TfmExample = class(TForm) 
 Panel1: TPanel; 
 bbRun: TBitBtn; 
 bbClose: TBitBtn; 
 edInput: TEdit; 
 lbOutput: TLabel; 
 mmOutput: TMemo; 
 procedure bbRunClick(Sender: TObject); 
 procedure FormActivate(Sender: TObject); 
end; 
var fmExample: TfmExample; 
implementation 
{$r *.dfm} 
// Объявление экспортируемых функций: 
function timeSetEvent(uDelay, uResolution: UInt; lpTimeProc: Pointer; 
 dwUser: DWord; fuEvent: UInt): Integer; stdcall; external 'winmm'; 
function timeKillEvent(uid: UInt): Integer; stdcall; external 'winmm'; 
// Объявление глобальных переменных 
var 
 ueventid: UInt; // Идентификатор события таймера 
 begtime: TDateTime; // Засекаем время< 
 counter: Integer; // Счетчик повторений 
 delay: Word; // Период срабатывания 
procedure procTime(uid, msg: UInt; dwuse, dw1, dw2: DWord); stdcall; 
// Реакция на срабатывание таймера (процедура обратного вызова) 
var h, m, s, ms: Word; // Переменные для декодирования времени 
const maxcount = 55; // Количество повторений 
begin 
 timeKillEvent(ueventid); // Останавливаем таймер 
 counter := counter+1; // Наращиваем счетчик 
 if counter = maxcount then // Конец цикла? 
 begin // - Да: декодируем время 
 DecodeTime((time-begtime)/maxcount, h, m, s, ms); 
 fmExample.mmOutput.Lines.Add( // Сообщаем результат 
 Format('Задано %s ms. Получено %d ms', 
 [fmExample.edInput.Text, ms])); 
 fmExample.edInput.Text := ; // Готовим повторение 
 fmExample.edInput.SetFocus;
 end 
 else // - Нет: вновь пускаем таймер 
 ueventid := timeSetEvent(delay, 0, @proctime, 0, 1); 
end; 
procedure TfmExample.bbRunClick(Sender: TObject); 
// Запускает таймер. edinput содержит требуемый период. 
begin 
 // Проверяем задание периода 
 if edInput.Text = then Exit; 
 try 
 delay := StrToInt(edInput.Text) 
 except 
 ShowMessage('Ошибка ввода числа'); 
 edInput.SelectAll; 
 edInput.SetFocus; 
 Exit 
 end; 
 counter := 0; // Сбрасываем счетчик 
 begtime := Time; // Засекаем время 
 // Запускаем таймер: 
 ueventid := timeSetEvent(delay, 0, @proctime, 0, 1); 
 if ueventid = 0 then 
 ShowMessage('Ошибка запуска таймера') 
end; 
procedure TfmExample.formactivate(Sender: TObject); 
begin 
 edInput.SetFocus 
end; 
end. 
Source: http://www.delphi.h5.ru/
ID: 00203