Компонент timer (таймер) служит для отсчета интервалов реального времени. Его свойство interval определяет интервал временив миллисекундах , который должен пройти от включения таймера до наступления события ontimer. Таймер включается при установке значения true в его свойство enabled. Единожды включенный таймер все время будет возбуждать события ontimer до тех пор, пока его свойство enabled не примет значения false.

Следует учесть, что в силу специфики реализации стандартного аппаратного таймера ibm-совместимого компьютера минимальный реально достижимый интервал отсчета времени не может быть меньше 55 мс (этот интервал называется тиком), более того, любой интервал времени, отсчитываемый с помощью таймера, всегда кратен 55 мс. Чтобы убедиться в этом, проведите эксперимент, в котором подсчитывается среднее время между двумя срабатываниями таймера (timer.dpr):

Начните новый проект с пустой формой и положите на нее компонент ttimer.
Установите в свойство enabled таймера значение false.
Напишите такой модуль главной формы (листинг 4):
Листинг 4

Code:

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}

 

procedure tfmexample.bbrunclick(sender: tobject);

// Запускает таймер. edinput содержит период его срабатывания.

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) с заголовком:

Code:

procedure timeproc(uid, umsg: uint; dwuser, dw1, dw2: dword); stdcall;

Здесь uid — идентификатор события таймера (см. об этом ниже); umsg — не используется; dwuser — произвольное число, передаваемое процедуре в момент срабатывания таймера; dw1, dw2 — не используются.

Запуск таймера реализуется функцией:

 

Code:

function timesetevent(udelay, uresolution: uint; lptimeproc: pointer; dwuser: dword; fuevent: uint): uint; stdcall; external'winmm.dll';

Здесь udelay — необходимый период срабатывания таймера (в мс); uresolution — разрешение таймера (значение 0 означает, что события срабатывания таймера будут возникать с максимально возможной частотой; в целях снижения нагрузки на систему вы можете увеличить это значение); lptimeproc — адрес процедуры обратного вызова; dwuser — произвольное число, которое передается процедуре обратного вызова и которым программист может распоряжаться по своему усмотрению; fuevent — параметр, управляющий периодичностью возникновения события таймера: time_oneshot (0) — событие возникает только один раз через udelay миллисекунд; time_periodic (1) — события возникают периодически каждые udelay мс. При успешном обращении функция возвращает идентификатор события таймера и 0, если обращение было ошибочным.

 

Таймер останавливается, и связанные с ним системные ресурсы освобождаются функцией:

 

Code:

function timekillevent(uid: uint): uint; stdcall; external'winmm.dll';

 

Здесь uid — идентификатор события таймера, полученный с помощью timesetevent.

В следующем примере (timer.dpr) иллюстрируется использование мультимедийного таймера (листинг 5).

 

Code:

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, ureolution: 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=0then

showmessage('Ошибка запуска таймера')

end;

 

procedure tfmexample.formactivate(sender: tobject);

begin

edinput.setfocus

end;

 

end.

Источник: https://www.delphi.h5

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить