Форум: "Основная";
Текущий архив: 2006.02.05;
Скачать: [xml.tar.bz2];
Внизпотоки и таймер Найти похожие ветки
← →
AKMTT (2006-01-08 23:07) [0]Доброго времени суток. Мне нужно сделать следующее: после запуска программы проходит некоторое время, к примеру 1 секунда, выполняется некторое действие. Делаю так:
type
TGameRead=class(TThread)
protected
procedure Execute;override;
procedure Tic;
end;
procedure TGameRead.execute;
begin
repeat
synchronize(Tic);
until Terminated
end;procedure TGameRead.Tic;
begin
.....
Beep;
end;
...
T1:=TGameRead.Create(false);
T1.Priority:=tpLowest;
Код взят из одной статьи.
Но 1ых, он работает не сразу после запуска, а через некоторый промежуток времени, и как проследить что прошла 1а секунда?
Проще говоря мне нужно заменить обычный таймер, чем-нибудь другим, не используя VCL
← →
VirEx © (2006-01-08 23:14) [1]{
Имя файла: HRTimer.PAS V1.00
Создан: Апр 17 1997, 06:40, автор John Mertus
Обновлен #6: Окт 12 1997, 10:56 John Mertus
Оболочка для таймера высокой точности при создании приложений под
Win95/WinNT
Var
HRT : THRTimer
HRT := THRTimer.Create;
HRT.StartTimer; Сброс таймера в ноль
HRT.ReadTimer; Возвращает отсчитанное время в миллисекундах
начиная со времени старта
HRT.Free;
Список изменений
Версия 1.00 - Первый выпуск
}
{-----------------Модуль HRTimer-------------------John Mertus Апрель 97---}
Unit HRTimer;
{-------------------Объявления-------------------------------}
interface
Uses Windows;
Type
THRTimer = Class(TObject)
Constructor Create;
Function StartTimer : Boolean;
Function ReadTimer : Double;
private
StartTime : Double;
ClockRate : Double;
public
Exists : Boolean;
End;
{--------------------------Реализация-----------------------------------}
implementation
{------------------Create-------------------------John Mertus----Мар 97-}
Constructor THRTimer.Create;
{ Получаем точное системное время и сохраняем его для дальнейшего }
{ использования. }
{ }
{***********************************************************************}
Var
QW : TLargeInteger;
BEGIN
Inherited Create;
Exists := QueryPerformanceFrequency(QW);
ClockRate := QW.QuadPart;
END;
{------------------StartTimer---------------------John Mertus----Мар 97-}
Function THRTimer.StartTimer : Boolean;
{ Получаем точное системное время и сохраняем его для дальнейшего }
{ использования. }
{ }
{***********************************************************************}
Var
QW : TLargeInteger;
BEGIN
Result := QueryPerformanceCounter(QW);
StartTime := QW.QuadPart;
END;
{-------------------ReadTimer---------------------John Mertus----Мар 97---}
Function THRTimer.ReadTimer : Double;
{ Получаем точное системное время и сохраняем его для дальнейшего }
{ использования. }
{ }
{***********************************************************************}
Var
ET : TLargeInteger;
BEGIN
QueryPerformanceCounter(ET);
Result := 1000.0*(ET.QuadPart - StartTime)/ClockRate;
END;
end.
← →
AKMTT (2006-01-08 23:19) [2]
ClockRate := QW.QuadPart;
Вот в этой строчке возникает ошибка:Record, object or class type required
← →
EvS (2006-01-08 23:27) [3]http://www.cracklab.ru/pro/delphi/Winapifa.php#00086D
← →
AKMTT (2006-01-08 23:30) [4]Ладно, всем спасибо, на GetTickCount остановился, ничего лучшего не нашел :(
← →
Piter © (2006-01-08 23:41) [5]Я честно говоря не понял.
Автору нужно отсчитать сколько прошло времени? Тогда GetTickCount.
Или нужно сделать свой таймер средствами WinApi? Тогда вот:
Вопрос: как создать таймер средствами Win32Api
Ответ: нужно воспользоваться функцией SetTimer, описанной в Windows.pas следующим образом:function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT;
lpTimerFunc: TFNTimerProc): UINT; stdcall;hWnd
- указатель на окно, куда будут посылаться сообщения WM_TIMER при очередной итерации таймераnIDEvent
- задает идентификатор таймера, не должен быть ноль. Игнорируется системой, если hWnd равно нулюuElapse
- время в миллисекундах между итерациями таймераlpTimerFunc
- указатель на процедеру TimepProc, которая должна являться callback функцией и которая будет вызываться системой при каждой итерации таймера
Видно, что существую два пути задания таймера - или задать окноhWnd
, куда будут посылаться сообщенияWM_TIMER
каждыеuElapse
миллисекунд, или задать указатель на процедуруlpTimerFunc
, которая будет вызываться системой каждыеuElapse
миллисекунд.
1) Рассмотрим первый вариант:procedure TForm1.Button1Click(Sender: TObject);
begin
if SetTimer(Handle, 1, 1000, nil)=0 then
ShowMessage("Не удалось создать таймер!");
end;
При успешном создании таймера, функцияSetTimer
вернет индентификатор таймера, который мы сами и задали - 1.
Если таймер создать не удалось - функция вернет ноль.
Если таймер создан, то экземпляру TForm1 каждые 1000 миллисекунд (1 секунду) будет посылаться сообщениеWM_TIMER
. Естественно, нужно это сообщение обрабатывать. УTForm1
объявить метод:TForm1 = class(TForm)
...
procedure WMTImer(var Msg: TMessage); message WM_TIMER;
...
И реализовать:procedure TForm1.WMTImer(var Msg: TMessage);
begin
beep;
end;
Каждую секунду будем издавать звуковой сигнал.
Чтобы удалить таймер, нужно вызвать функциюKillTimer
, передав ейHandle
окна и идентификатор таймера (которые указывали при создании таймера) .KillTimer(Handle, 1);
Стоит заметить, что если в очереди потока стоит хотя бы одно необработанное сообщение от таймера - то новое сообщение от таймера в очередь помещаться не будет. Мicrosoft, наверное, это сделал специально, чтобы исключить забиение очереди необработанными сообщениями какого-то не в меру шустрого таймера по отношению к обработчикам остальных сообщений
2) теперь рассмотрим второй варинт, на основе процедуры TimerProc. Вызов будет такой:idTimer := SetTimer(0, 0, 1000, @TimerProc);
if idTimer=0 then
ShowMessage("Не удалось создать таймер!");
В качестве указателя на окно пишем ноль, во второй параметр пишем что хотим (все равно игнорируется), третий - время итераций, четвертый - указатель на процедуруTimerProc
, которая будет вызываться системой каждые 1000 миллисекунд. Где-то должна быть объявлена и реализована эта процедураTimerProc
(получается, что это callback процедура, значит соглашение о вызове должно быть stdcall, не забывайте):procedure TimerProc(wnd: HWND; Msg: UINT; idEvent: UINT; Time: DWORD); stdcall;
begin
beep;
end;
Гдеwnd
- указатель на окно, которое передали функцииSetTimer
(в нашем случае ноль);Msg
- номер сообщения (оно будет равноWM_TIMER
);idEvent
- идентификатор таймера (тоже значение, которое вернетSetTimer
и которое записано вidTimer
);Time
- время в миллисекундах, которое прошло с момента загрузки Windows на момент генерации этого события таймера (данное значение эквивалентно тому, что возвращает функцияGetTickCount
).
Делает этот код тоже самое, что и первый пример - издает сигнал каждую секунду. При этом никакие передаваемые аргументы я не анализирую. Хотя, например, можно создать два таймера и назначить им одинаковуюTimerProc
. А различать вызовы от одного и другого таймеров по значениюidEvent
.
Значение, возвращаемое функциейSetTimer
сохраняется в какую-нибудь переменнуюidTimer: UINT
. Это нужно, чтобы потом можно было удалить таймер, так как во втором примере id таймера назначется системой.
Стоит отметить, что функцияTimerProc
вызывается системой в контексте того потока, который вызвал функциюSetTimer
для установки таймера. Причем вызовTimerProc
происходит неявно при вызове приложением функцииDispatchMessage
, поэтому если приложение не делает выборки и диспетчеризации сообщений - то вызоваSetTimer
не будет.
Чтобы удалить таймер, надо просто вызвать функию KillTimer, передав ей Handle окна (который указывали при создании таймера) и идентификатор таймера (которое вернула система).KillTimer(0, idTimer);
3) Есть еще и третий вариант - не указывать ни handle окна, ни процедуру TimerProc:idTimer := SetTimer(0, 0, 1000, nil);
Тогда система просто будет посылать сообщениеWM_Timer
в очередь потока, который вызвалSetTimer
.
В главном потоке отловить такое сообщение можно назначив обработку Application.OnMessage:...
Application.OnMessage := OnAppMessage;
...
procedure TForm1.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Msg.message = WM_TIMER then
begin
beep;
Handled := True;
end;
end;
При этом какой бы цикл выборки сообщений в потоке не был - нельзя допускать вызоваDispatchMessage
, так как ведь у этого сообщения Handle=0, а значит оно не будет диспетчеризировано. Поэтому доApplication.OnMessage
это сообщение "доходит", а вот доApplication.DefaultHandler
не дойдет.
Файл проекта с данными примерами можно загрузить ЗДЕСЬ
Отвечали: Piter, Ihor Osov"yak
← →
begin...end © (2006-01-09 09:26) [6]CreateWaitableTimer
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2006.02.05;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.011 c