- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Delphi. Трюки и эффекты - Валерий Борисок
Шрифт:
Интервал:
Закладка:
Аппаратный таймер
Следующий рассматриваемый способ измерения времени основан на использовании таймера высокого разрешения (высокочастотного). Временной промежуток между «тиками» этого таймера может быть намного меньше 1 мс, что позволяет производить достаточно точные измерения. Для сохранения количества «тиков» аппаратного таймера используется 64-битный счетчик.
Пример получения значения счетчика аппаратного таймера приводится в листинге 7.8. Частота, возвращаемая функцией hwTimerGetCounter, измеряется в Гц (с-1), то есть означает количество срабатываний таймера в 1 с.
...Листинг
7.8. Получение значения счетчика аппаратного таймера
function hwTimerGetCounter(): Int64;
var
freq: Int64;
begin
if QueryPerformanceCounter(freq) <> False then
hwTimerGetCounter := freq
else
hwTimerGetCounter := 0; //Ошибка
end;
Чтобы перевести количество «тиков» аппаратного таймера в привычные нам единицы измерения, нужно узнать его частоту. В этом нам поможет функция, приведенная в листинге 7.9.
...Листинг 7.9.
Определение частоты аппаратного таймера
function hwTimerGetFreq(): Int64;
var
freq: Int64;
begin
if QueryPerformanceFrequency(freq) <> False then
hwTimerGetFreq := freq
else
hwTimerGetFreq := 0; //Ошибка
end;
Пусть нам известна разность между значения счетчика в начале и конце измерения. Перевести ее в секунды можно следующим образом:
...time:= counter div hwTimerGetFreq();
Пример, а точнее, результат определения характеристик аппаратного таймера приведен на рис. 7.4.
Рис. 7.4. Характеристики аппаратного таймера
Заполнение приведенных на рис. 7.4 текстовых полей осуществляется чрезвычайно просто, поэтому код, описывающий это, в тексте не приводится. При желании вы сможете найти его на диске, прилагаемом к книге, в папке с названием раздела.
Мультимедиа-таймер
Рассмотрим еще один способ измерения, основанный на использовании так называемого мультимедиа-таймера. Его использование удобно тем, что появляется возможность задания его точности. Группа API-функций работы с мультимедиа-таймером позволяет не только измерять временные интервалы, но и создавать программные таймеры (см. компонент Timer), срабатывающие через гораздо меньшие промежутки времени.
Для получения текущего значения счетчика мультимедийного таймера можно воспользоваться функцией timeGetTime. Вообще, она возвращает значения, аналогичные значениям, возвращаемым функцией GetTickCount. Счетчик также 32-битный, обнуляемый приблизительно каждые 49,7 суток. Прототип функции timeGetTime следующий:...function timeGetTime: DWORD; stdcall;
Пример использования этой функции приведен в листинге 7.12, а теперь несколько слов о том, как получить для рассматриваемого таймера значения минимальной и максимальной точности. Для получения этих данных можно использовать функцию timeGetDevCaps. Она принимает в качестве параметра структуру TTimeCaps и заполняет два ее поля соответствующими значениями. В листинге 7.10 приводится возможная реализация функций для определения характеристик мультимедийного таймера.
...Листинг 7.10.
Определение характеристик мультимедиа-таймера
//Получение максимального периода таймера (мс)
function timeGetMaxPeriod(): Cardinal;
var
time: TTimeCaps;
begin
timeGetDevCaps(Addr(time), SizeOf(time));
timeGetMaxPeriod := time.wPeriodMax;
end;
//Получение минимального периода таймера (мс)
function timeGetMinPeriod(): DWORD;
var
time: TTimeCaps;
begin
timeGetDevCaps(Addr(time), SizeOf(time));
timeGetMinPeriod := time.wPeriodMin;
end;
Итак, мы знаем, как получать параметры таймера. Но было сказано, что его точность можно регулировать. Делается это при помощи функций timeBeginPeriod и timeEndPeriod.
• Первая функция вызывается для установления минимальной точности таймера, которая устраивает приложение. Функция timeBeginPeriod принимает значение требуемой точности таймера в миллисекундах, возвращает TIMERR_NOERROR в случае успеха либо Т IMERR_NOCANDO, если требуемая точность не может быть обеспечена.
• Вторая функция восстанавливает точность таймера такой, какой она была до вызова функции timeBeginPeriod. В функцию timeEndPeriod должно передаваться то же значение, что и в функцию timeBeginPeriod.
В листинге 7.11 показано использование функци и timeBeginPeriod, атакже timeEndPeriod (реализованы функции-оболочки). При пользовании функциями из листинга 7.11 нужно помнить, что после вызова timeSetTimerPeriod и проведения измерения обязательно должна быть вызвана timeRestoreTimerPeriod. Функция timeSetTimerPeriod сохраняет значение установленной точности таймера в глобальной переменной lastPeriod, чтобы можно было не заботиться о сохранении этого значения в коде, использующем таймер.
...Листинг 7.11. Функции изменения точности таймера
Var lastPeriod: Cardinal;
//Установка периода таймера (мс) перед началом измерения
function timeSetTimerPeriod(period: Cardinal): Boolean;
begin
if timeBeginPeriod(period) = TIMERR_NOERROR then
begin
//Сохраним значение для восстановления состояния таймера
lastPeriod := period;
timeSetTimerPeriod := True;
end
else
//Неудача
timeSetTimerPeriod := False;
end;
//Восстановление периода таймера (обязательно)
function timeRestoreTimerPeriod(): Boolean;
begin
if timeEndPeriod(lastPeriod) = TIMERR_NOERROR then
timeRestoreTimerPeriod := True
else
timeRestoreTimerPeriod := False;
end;
Теперь, после долгого рассмотрения особенностей настройки мультимедиа-таймера, приведем пример его использования для измерения времени выполнения простейшего отрезка программы (листинг 7.12).
...Листинг 7.12.
Измерение времени выполнения отрезка программы
procedure TForm1.cmbTimeGoClick(Sender: TObject);
var
summ, arg, maxVal: Int64;
startTime, endTime: Cardinal;
begin
txtTimeResult.Text := 'Измерение…
Refresh;
maxVal := StrToInt(txtTimeMaxVal.Text);
//Устанавливаем маскимальную точность таймера
timeSetTimerPeriod(timeGetMinPeriod());
startTime := timeGetTime(); //Начальный момент времени
//Суммируем 64-битные числа
//(как раз и измеряем время его выполнения)
summ := 0;
arg := 1;
while (arg <= maxVal) do
begin
Inc(summ, arg);
Inc(arg);
end;
endTime := timeGetTime(); //Конечный момент времени
//Восстанавливаем период таймера
timeRestoreTimerPeriod();
//Время выполнения операций (мс)
txtTimeResult.Text := IntToStr(endTime – startTime);
end;
Создание программного таймера высокой точности
В самом начале рассмотрения возможностей мультимедиа-таймера было сказано, что в его API заложена возможность создания программных таймеров. Это действительно так. Причем максимальная точность такого таймера может получиться довольно большой: на современных компьютерах создание программного таймера с периодом срабатывания 1 мс – не проблема. Правда, использовать максимальную частоту таймера вряд ли стоит: слишком велика вероятность ошибки как минимум на 1 мс.
Теперь уясним, что же за программный таймер мы создаем и чем он отличается от компонента Timer, помещаемого на форму. А отличается наш таймер, кроме высокой точности, тем, что его не нужно привязывать к окну (форме): при срабатывании стандартного компонента Timer окну, за которым он закреплен, посылается сообщение WM_TIMER. Создаваемый же нами таймер работает по-другому, что удобнее рассмотреть на примере.
...timerID := timeSetEvent
(
StrToInt(txtTimeInterval.Text), //Интервал между
//срабатываниями таймера
timeGetMinPeriod(), //Точность таймера
TimerProc, //Адрес процедуры, вызываемой при каждом
//срабатывании таймера
0, //Параметр, передаваемый в процедуру
//обратного вызова
TIME_CALLBACK_FUNCTION or TIME_PERIODIC //Тип таймера
);
В приведенном выше отрывке программы с помощью функции timeSetEvent происходит регистрация и запоминание адреса процедуры TimerProc, вызываемой периодически при срабатываниях таймера. При успешном создании таймера функция timeSetEvent возвращает ненулевое значение – идентификатор созданного таймера. Оно может использоваться в дальнейшем для определения, какой именно таймер сработал. Значение, возвращенное функцией timeSetEvent, также необходимо при удалении таймера:
...timeKillEvent(timerlD);
Функция timeKillEvent возвращает целочисленное значение:
• TIMERR_NOERROR – если ее вызов завершился успешно;
• MMSYSERR_INVALPARAM – если таймера, заданного параметром функции, не существует.
Теперь о процедуре, адрес которой мы передаем в функцию timeSetEvent. В нашем примере она выглядит следующим образом (листинг 7.13).
...Листинг 7.13.
Процедура, вызываемая при срабатывании таймера
procedure TimerProc(uTimerID, uMessage: UINT; dwUser, dw1, dw2:
DWORD) stdcall;
begin
//Добавляем текущее значение времени в список (чтобы была
//видна разница между моментами вызова этой процедуры)
Form1.lstTimes.Items.Add(IntToStr(timeGetTime()));
end;
Естественно, действия, выполняемые процедурой TimerProc, могут быть самыми различными. В нашем случае происходит заполнение списка (List) значениями счетчика «тиков» таймера на момент вызова процедуры (рис. 7.5).
Рис. 7.5. Результат работы таймера
В завершение вновь обратимся к функции timeSetEvent: кратко перечислим предоставляемые ею возможности, которыми мы не воспользовались в приведенном выше примере.
Как вы могли заметить, последний параметр функции timeSetEvent является битовой маской. Флаги этой маски задают два аспекта поведения таймера: количество срабатываний таймера и тип действия, которое требуется выполнять при срабатывании таймера.

