Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.06.14;
Скачать: CL | DM;

Вниз

Функции SeTimer, KillTimer   Найти похожие ветки 

 
ChtoMe   (2005-04-21 17:48) [0]

У меня проблема с работой функций SetTimer и KillTimer. Проблема в следующем: в моей программе нету формы поэтому код, который не работает слудующий:
program Project1;

uses
 windows,messages,sysutils,dialogs;

var
 temer,cont:integer;

{$R *.res}

procedure getting(hnd:HWND;uMsg:UINT;tem:UINT;tickt:DWORD);

begin
  inc(cont);
  inputbox("1","","");
  if cont>5 then killtimer(0,temer);       //если судить по  //документации, то вместо temer можно использовать tem, но толку //от этого мало
end;

begin
 cont:=0;
 temer:=settimer(0,0,100,@getting);
 inputbox(bla-bla-bla","","");
end.

По моей задумке должен вылезти inputbox 5 раз после чего таймер должен убиться функцией killtimer, но inputbox у меня вылазеет гораздо больше чем 5 раз. Короче программа зацикливается.
Подскажите, может я чё-то не так делаю? И если у кого есть пример как правильно работать с таймером без формы скажите где взять плиз или скиньте на jeon@inbox.ru


 
alpet ©   (2005-04-21 18:08) [1]

Второй Параметр должен быть не нулевой.
nIDEvent
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.


 
alpet ©   (2005-04-21 18:08) [2]

Второй Параметр должен быть не нулевой.
nIDEvent
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.


 
Digitman ©   (2005-04-21 18:09) [3]

ты, чудо, вообще-то титал описание ф-ции SetTimer в стандартной справке ?


 
alpet ©   (2005-04-21 18:11) [4]

+ про соглашение stdcall как всегда забыл.

В C++:
VOID CALLBACK TimerProc(HWND hwnd,
   UINT uMsg,
   UINT_PTR idEvent,
   DWORD dwTime
);

В Delphi должно быть как:
procedure (hwnd, uMsg, nEvent, dwTime: DWORD); stdcall;
begin
end;


 
alpet ©   (2005-04-21 18:13) [5]

alpet ©   (21.04.05 18:08) [2]
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored. If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.

Вернее наоборот, нулевой когда hWnd = 0. Сам ошибся.


 
alpet ©   (2005-04-21 18:15) [6]

Если уж совсем точно - то без разницы какой, если не указано окно, но есть callback фукнция.


 
KosilkA ©   (2005-04-21 18:17) [7]


>
> ChtoMe   (21.04.05 17:48)  


може так...
procedure getting(hnd:HWND;uMsg:UINT;tem:UINT;tickt:DWORD);
begin
 KillTimer(temer);  inc(cont);
 inputbox("1","","");
 if cont>5 then killtimer(0,temer) else
 temer:=SetTimer(0,0,100,@getting);
end;


 
alpet ©   (2005-04-21 18:19) [8]

KosilkA ©   (21.04.05 18:17) [7]

Очень смешно :-). Только не будет работать.


 
KosilkA ©   (2005-04-21 18:20) [9]

да и вообще, чего париться, если в uses стоит dialogs то не грех и forms добавить и таймер с палитры кинуть, все равно на весе уже не сэкономишь =))))


 
KosilkA ©   (2005-04-21 18:20) [10]


> alpet ©   (21.04.05 18:19) [8]

а ты пробовал? =))


 
alpet ©   (2005-04-21 18:28) [11]

KosilkA ©   (21.04.05 18:20) [10]
а ты пробовал? =))


нет, и дисскусию прекращаем. Всего что не хватает ChtoMe - умения пользоваться отладчиком. Управление ветке if count > 5 ни когда не передается из-за вызова модального диалога.


 
ChtoMe   (2005-04-21 18:35) [12]

Спасибо, так работает, но некоторые моменты не понятны. Зачем добавлять stdcall? Чем функция с stdcall отличается от простой?

И вот ещё не ясно:(hwnd, uMsg, nEvent, dwTime: DWORD);?
А где же тут тип передаваемыхь переменных? Ваще не врублюсь...


 
KosilkA ©   (2005-04-21 18:36) [13]


> alpet ©   (21.04.05 18:28) [11]

прям таки никогда?


 
ChtoMe   (2005-04-21 18:39) [14]

Кстати насчёт if count>5    -  это я внатуре тупанул, что сначала вызывал это с inputbox!!!

И что такое stdcall?


 
KosilkA ©   (2005-04-21 18:39) [15]


> ChtoMe   (21.04.05 18:35) [12]
> Спасибо, так работает, но некоторые моменты не понятны.
> Зачем добавлять stdcall? Чем функция с stdcall отличается
> от простой?
>
> И вот ещё не ясно:(hwnd, uMsg, nEvent, dwTime: DWORD);?
> А где же тут тип передаваемыхь переменных? Ваще не врублюсь...

ты лучше задайся вопросом, правильно ли то , что у тебя вместо того чтобы по очереди, программа выплевывает сразу пять диалогов, нафига тебе такое нужно?=))


 
alpet ©   (2005-04-21 18:41) [16]

Зачем добавлять stdcall? Чем функция с stdcall отличается от простой?

Параметры передаются в стеке обратном порядке по отношению к PASCAL, и не в регистрах как в register.

Directive Parameter order Clean-up Passes parameters in registers?
register Left-to-right Routine Yes
pascal Left-to-right Routine No
cdecl Right-to-left Caller No
stdcall Right-to-left Routine No
safecall Right-to-left Routine No


А где же тут тип передаваемыхь переменных? Ваще не врублюсь

А DWORD что такое, или ты к каждой переменной тип прописываешь?


 
alpet ©   (2005-04-21 18:44) [17]

KosilkA ©   (21.04.05 18:36) [13]

прям таки никогда?

До тех пор пока пользователь не закроет хотя бы один диалог, они будут появляться... до переполнения стека или исчерпания ресурса hwnd. В любом случае логика в коде нарушена.


 
ChtoMe   (2005-04-21 18:45) [18]

Ясно... Большое спасибо.


 
KosilkA ©   (2005-04-21 18:56) [19]


> alpet ©   (21.04.05 18:44) [17]
> KosilkA ©   (21.04.05 18:36) [13]
>
> прям таки никогда?
>
> До тех пор пока пользователь не закроет хотя бы один диалог,
> они будут появляться... до переполнения стека или исчерпания
> ресурса hwnd. В любом случае логика в коде нарушена.

а попробовать не судьба прежде чем так безапеляционно? =))


 
KosilkA ©   (2005-04-21 19:11) [20]

... и вообще, чо тут за пурга??? зачем таймер тут нужен???? Штоб пять диалогов показать? А в цикле нельзя штоли?  блин, пора домой


 
ChroMe ©   (2005-04-21 19:17) [21]

Ещё появилась одна проблема...
После вызова SetTimer работа программы останавливается так как после этой строчки стоит end. Короче таймер не успевает выполниться не разу. Что с этим можно поделать? Чтобы программа не закрывалась. Пробовал sleep(), но не помогло. Я слышал, что программу можно сделать процессом, но как не знаю или подскажите другой вариант. И как потом закрыть программу, которая будет висеть как процесс? Вот код, который у меня получился в итоге:

procedure getting(hwnd, uMsg, nEvent, dwTime: DWORD);stdcall;
var
 s:string;
 f:textfile;
begin
  inc(cont);
  if cont>5 then killtimer(0,temer);
  assignfile(f,"c:\2.txt");
  rewrite(f);
  str(cont,s);
  writeln(f,s);
  closefile(f);
end;

begin
 cont:=0;
 temer:=settimer(0,0,100,@getting);
end.


 
alpet ©   (2005-04-21 19:18) [22]

KosilkA ©   (21.04.05 18:56) [19]
а попробовать не судьба прежде чем так безапеляционно? =))


Попробуй лучше этот код:
while Random (1000000) > 0 do;
ShowMessage ("ok");

Его выполнение будет не гарантированным, но тем не менее очень интересным.

... и вообще, чо тут за пурга??? зачем таймер тут нужен???? Штоб пять диалогов показать? А в цикле нельзя штоли?  блин, пора домой

Не в цикле не катит, надо чтобы диалоги появлялись без закрытия. Пора ТЗ.


 
ChroMe ©   (2005-04-21 19:21) [23]

Нет таймер нужен для другого, просто пробую на чём получиться, а потом вставлю код, который мне нужен.


 
alpet ©   (2005-04-21 19:29) [24]

2 ChtoMo

Вообще зачем ты таймер создаешь для таких целей? Прямой вызов в цикле чем хуже?

И как может работать таймер без единого открытого окна принимающего WM_TIMER ?


 
alpet ©   (2005-04-21 19:32) [25]

Если окно не хочешь создавать попробуй так

....
var msg: tagMsg;
begin
cont:=0;
temer:=settimer(0,0,100,@getting);
while (cont < 5) and GetMessage (msg, 0, 0, 0) do
    DispatchMessage (msg);
end.


 
KosilkA ©   (2005-04-22 10:30) [26]


> alpet ©   (21.04.05 19:18) [22]
> KosilkA ©   (21.04.05 18:56) [19]
> а попробовать не судьба прежде чем так безапеляционно? =))
>
> Попробуй лучше этот код:
> while Random (1000000) > 0 do;
> ShowMessage ("ok");
> Его выполнение будет не гарантированным, но тем не менее
> очень интересным.


и чем же интересно выполнение данного кода ? Random"ом? Да,я потрясён


 
alpet ©   (2005-04-22 10:47) [27]

>и чем же интересно выполнение данного кода ? Random"ом? Да,я потрясён

А ты попробывал ? Под отладчиком ?
Короче хватит оффтопа, я хотел сказать что бессмыссленный код и анализировать бессмысленно.


 
KosilkA ©   (2005-04-22 10:57) [28]

> бессмыссленный код и анализировать бессмысленно

бессмысленно охаивать то, чего так и не удосужился попробовать


 
Alexander Panov ©   (2005-04-22 11:01) [29]

Так что же все-таки автор топика хочет сделать?
Зачем таймер?
Бессмысленно давать советы непонятно для чего.


 
alpet ©   (2005-04-22 11:32) [30]

2 KosilkA

[11] - относилось к [1], и тут все верно.
в  [7] - всего одна ошибка и не в логике, а тексте - пробывать этот код опять же бессмыслено, если и так ясно как он себя поведет.

Автору сабжа, видимо хочется научится работать с таймером, но он похоже пока плохо представляет как этот таймер организуется и вообще весь механизм сообщений Windows.


 
KosilkA ©   (2005-04-22 11:51) [31]


> alpet ©   (22.04.05 11:32) [30]

учитывая , что ты пишешь слово пробЫвать с буквой Ы, я снимаю с себя ответственность в отсутствии нуля в вызове KillTimer :o)


 
Piter ©   (2005-04-22 12:02) [32]

Вопрос: как создать таймер средствами 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


 
ChroMe ©   (2005-04-23 00:42) [33]

Ребят всем спасибо... Мне нужно именно наичиться работать с таймером, чтобы не занимать компонентом-таймером лишние килобайты в своей проге.



Страницы: 1 вся ветка

Текущий архив: 2005.06.14;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.181 c
3-1115900109
pavel_guzhanov
2005-05-12 16:15
2005.06.14
вопрос про DBGrid


1-1117344094
VasilijOrlov
2005-05-29 09:21
2005.06.14
как мне сделать, чтобы пользователь щелкнул, изменил, закрыл и вс


14-1117095731
Nic87
2005-05-26 12:22
2005.06.14
Вопрос модераьорам


14-1116835841
Yuri Btr
2005-05-23 12:10
2005.06.14
Проблема с маршрутизацией???


1-1117292661
twin
2005-05-28 19:04
2005.06.14
Excel и графики