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

Вниз

Timer.OnTimer   Найти похожие ветки 

 
Separator ©   (2003-01-06 10:49) [0]

Может ли не срабатывать событие OnTimer, если я создаю таймер в отдельном потоке?


 
Дмитрий К.К. ©   (2003-01-06 11:33) [1]

Может. Если свойство Enabled компонента Timer равняется False.


 
Separator ©   (2003-01-06 12:01) [2]

Да нет с этим все впорядке, я даже OnTimer переопределил.
Ситуация вообще такая:

type
TKvit = class
private
arrTimerKvit: array [0..CountKvit - 1, 0..(CountPars - 1)] of TTimer;
public
constructor Create;
destructor Destroy; override;
procedure TimerKvit(Sender: TObject);
procedure Enabled(Par, Bit: byte);
procedure Disabled(Par, Bit: byte);
end;

TgbAutoThread = class(TThread)
protected
Kvit: TKvit;
procedure GetBits;
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
end;

implementation

constructor TgbAutoThread.Create(CreateSuspended: Boolean);
var
i, j: byte;

begin
inherited Create(CreateSuspended);
Kvit:= TKvit.Create
end;

procedure TKvit.Enabled(Par, Bit: byte);
begin
arrTimerKvit[Bit, Par]:= TTimer.Create(nil);
with arrTimerKvit[Bit, Par] do
begin
Enabled:= false;
OnTimer:= TimerKvit;
Interval:= 5000;
Enabled:= true
end
end;

procedure TKvit.TimerKvit(Sender: TObject);
begin
// Не срабатывает
end;




 
Набережных С.   (2003-01-06 12:27) [3]

В Execute нужен цикл выборки сообщений.


 
Separator ©   (2003-01-06 12:30) [4]

Каких сообщений?


 
Набережных С.   (2003-01-06 12:45) [5]

windows messages


 
Mystic ©   (2003-01-06 12:52) [6]

Проще поискать другое решение. Например, создать в потоке окно, средствами API, создать Timer и вручную ловить сообщение WM_TIMER. Но в большинсве случаев можно предложить и более простой вариант (например создавать Timer в контексте основного потока).

Библиотека VCL рассчитана на однопоточные применения. Даже если ты добьешься работоспособности кода, никто не даст гарантий, что с переходом на новую версию Delphi он у тебя останется рабочим.

Delphi 6, VCL: Объект Timer регистрирует функцию обработки сообщений (вызов Classes.AllocateHWnd), создает объект Timer Windows и ловит WM_TIMER. Функция Classes.AllocateHWnd создает окно, но поскольку она создает его в другом потоке, то все сообщения этого окна будут посылаться в этот поток (тут есть даже возможность, что окно вообще не создасться, так как не ответит на несколько стандартных сообщений)...

Если тебе непонятно о чем здесь говорится, то лучше скажи, какого эффекта ты собираешься добиться, может можно это сделать другим путем.


 
Separator ©   (2003-01-06 12:53) [7]

И как мне это сделать?


 
Separator ©   (2003-01-06 13:00) [8]


> Mystic © (06.01.03 12:52)
Я решил создавать Timer в основном потоке, сейчас эксперементирую


 
Набережных С.   (2003-01-06 13:24) [9]

>Mystic © (06.01.03 12:52)

>Функция Classes.AllocateHWnd создает окно, но поскольку она создает его в другом потоке

С чего бы вдруг? Из какого потока вызвали конструктор таймера, в том и создаст. А потокобезопасность здесь обеспечить очень просто. Например, ожидая окончания инициализации потока.


 
Separator ©   (2003-01-06 13:26) [10]

Все равно почемуто не работает:

type
TfrmMain = class(TForm)
..............
private
Kvit: TKvit;
arrTimerKvit: array [0..CountKvit - 1, 0..(CountPars - 1)] of TTimer;
procedure TimerKvit(Sender: Object)
.......

даже в таком случае, OnTimer, почему-то не срабатывает


 
Mystic ©   (2003-01-06 13:28) [11]


> Набережных С.


В приведенном выше примере кода поток создает экземпляр TKvit, таймеры объявлены как поля TKvit, вот я и предположил, что вызов AllocateHWnd производится из другого потока


 
Mystic ©   (2003-01-06 13:30) [12]

> Separator

Мало кода


 
Набережных С.   (2003-01-06 13:41) [13]


TTimerThread = class(TThread)
private
FTimer: TTimer;
FCount: integer;
FEvent: THandle;
procedure OnTimerEvent(Sender: TObject);
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; Event : THandle);
end;

var
Thr: TTimerThread;

procedure TForm1.SpeedButton3Click(Sender: TObject);
var
Event: THandle;
begin
Event:=CreateEvent(nil,false,false,nil);
Thr:=TTimerThread.Create(true,Event);
with Thr do
begin
FreeOnTerminate:=true;
Resume;
end;
WaitForSingleObject(Event,10000);
end;

procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
if Thr <> nil then Thr.Terminate;
end;

{ TTimerThread }

constructor TTimerThread.Create(CreateSuspended: Boolean; Event: THandle);
begin
FEvent:=Event;
inherited Create(CreateSuspended);
end;

procedure TTimerThread.Execute;
var
s: string;
Msg: TMsg;
begin
FTimer:=TTimer.Create(nil);
SetEvent(FEvent);
try
FTimer.OnTimer:=OnTimerEvent;
while GetMessage(Msg,0,0,0)do
begin
DispatchMessage(Msg);
if Terminated then Break;
end;
finally
FTimer.Free;
s:=IntToStr(FCount);
MessageBox(0,PChar(s),"",MB_SYSTEMMODAL);
end;
end;

procedure TTimerThread.OnTimerEvent(Sender: TObject);
begin
Inc(FCount);
end;


Проверки добавь.



 
Separator ©   (2003-01-06 13:51) [14]

Ладно завтра доработаю, посмотрю еще, а сейчас уже конец рабочего дня у меня


 
Набережных С.   (2003-01-06 13:56) [15]

Червь гложет:)
Не забудь Event закрыть. Лучьше сразу после WaitForSingleObject.


 
vuk ©   (2003-01-06 14:56) [16]

Если не планируется использовать софт в ОС отличных от NT/W2K/XP, то можно использовать WaitableTimer. Такие таймеры можно использовыть с функциями WaitForSingleObject/WaitForMultipleObjects.

Готовый класс для работы с такими таймерами:
http://delphibase.endimus.com/?action=viewfunc&topic=sysiface&id=10016



 
Separator ©   (2003-01-07 11:25) [17]

Вот кусок моего кода:

const
CountPars = 14; //Количество структур
CountKvit = 3; //Количество битов квитирования

type
TfrmMain = class(TForm)
private
arrTimerKvit: array [0..CountKvit - 1, 0..(CountPars - 1)] of TTimer; //Массив таймеров
FflgKvit: boolean; //Флаг квитирования
procedure SetflgKvit(const Value: boolean);
public
procedure OnTimerKvit(Sender: TObject); //Событие таймера
procedure EnabledTimer(Par, Bit: byte); //Создание и запуск таймера
procedure DisabledTimer(Par, Bit: byte); //Уничтожение таймера
procedure DisabledAll; //Уничтожение всех таймеров
property flgKvit: boolean read FflgKvit write SetflgKvit; //Флаг квитирования
end;

implementation

procedure TfrmMain.DisabledTimer(Par, Bit: byte); //Уничтожение таймера
begin
if arrTimerKvit[Bit, Par] <> nil then
begin
arrTimerKvit[Bit, Par].Destroy;
arrTimerKvit[Bit, Par]:= nil
end
end;

procedure TfrmMain.DisabledAll; //Уничтожение всех таймеров
var
i, j: integer;

begin
for i:= 0 to CountPars - 1 do
for j:= 0 to CountKvit - 1 do
DisabledTimer(i, j)
end;

procedure TfrmMain.EnabledTimer(Par, Bit: byte); //Создание и запуск таймера
begin
frmMain.arrTimerKvit[Bit, Par]:= TTimer.Create(self);
with frmMain.arrTimerKvit[Bit, Par] do
begin
Parent:= self;
Name:= "Timer" + IntToStr(Bit) + "_" + IntToStr(Par);
OnTimer:= frmMain.OnTimerKvit;
Interval:= 5000;
Enabled:= true
end
end;

procedure TfrmMain.SetflgKvit(const Value: boolean); //Установка флага квитирования
begin
FflgKvit := Value;
if Value then
frmMain.btnAutoGetBits.Enabled:= false
else
frmMain.btnAutoGetBits.Enabled:= true
end;

procedure TfrmMain.OnTimerKvit(Sender: TObject); //Событие OnTimer
begin
if not flgKvit then
begin
DisabledAll;
SetflgKvit(true);
pcSignal.ActivePageIndex:= 0;
with btnKvit do
begin
Enabled:= true;
SetFocus
end;
JumpUp;
AddHistory("Запуск звуковой сигнализации");
with TimerKvitEnabled do
begin
Interval:= 1000 * 60 * 10;
Enabled:= true
end;
SoundThread.Resume
end
end;


Проблема все в том же, событие OnTimer не наступает.
Процедуры EnabledTimer и DisabledTimer вызываются из отдельного потока


 
Набережных С.   (2003-01-07 13:48) [18]

>Separator © (07.01.03 11:25)
>Процедуры EnabledTimer и DisabledTimer вызываются из отдельного потока

Давай код этого потока.


 
Separator ©   (2003-01-07 14:22) [19]

Код всего потока давать бессмыслено, он очень большой. А принцип там такой: Поток считывает данные с MySQl сервера, в завасимости от приходящих данных и вызываются процедуры EnabledTimer и DisabledTimer, вот его часть:

if (StBinLast[i, N] = "1") and (StBin[N] = "0") then
frmMain.EnabledTimer(i, 0)
else
frmMain.DisabledTimer(i, 0);


StBinLast -> последний набор данных, StBin -> текущий набор данных
Так вот если происходит переключение с 1 на 0, то должен запуститься таймер, а если с 0 на 1, то он должен остановиться. Если таймер не остановиться и сработает, то тогда выдается предупреждение и всякая другая фигня. Самое интересно, что таймеры создаются и уничтожаются, но вот событие OnTimer не происходит.

Вообще может в чем и другом ошибка, так как код еще не доведен до ума, но вроде все остальное нормально работает.

Кстати когда я просто бросал 1 Timer на форму и его запускал и останавливал все работало, но в том то и дело, что Timer должен быть не один, а n-ное количество, заранее неизвестное.


 
Набережных С.   (2003-01-07 14:56) [20]

Чтобы OnTimer происходили нужно, чтобы Execute был построен примерно как показано (>Набережных С. (06.01.03 13:41)), при этом они будут происходить в контексте именно этого, создавшего таймеры, потока. Следует также обеспечить проверку Terminated независимо от поступающих сообщений(или просто вместо вызова Terminate посылать потоку WM_QUIT) и потокобезопасность уничтожения таймеров. Причем уничтожать нужно в том же потоке, который их создавал. Вообще у меня сложилось впечатление, что ты совсем не ориентируешься в работе с потоками. Лучше досконально разберись сначала с примерами из Demos. А ты вообще-то уверен, что тебе нужны таймеры в дополнительных потоках? Может, ну их к лешему? Больше мне добавить нечего. Удачи.


 
Separator ©   (2003-01-07 15:14) [21]

Я ведь создаю таймеры не в дополнительных потоках, из дополнительного потока просто вызывается процедура, которая и создает таймер


 
Separator ©   (2003-01-07 15:15) [22]

А честно я и правда не совсем разбираюсь в работе отдельных потоков :)


 
Набережных С.   (2003-01-07 15:55) [23]

>Separator © (07.01.03 15:15)

А без этого все бесполезно. Почитай справку, Рихтера. Погоняй примеры в пошаговом режиме, отслеживая активность потоков на каждом шаге в окне Threads отладчика. Когда разберешься, пересмотришь всю структуру своей проги.


 
Separator ©   (2003-01-08 06:07) [24]

Все заработало, просто я сначала при OnCreate формы создал все таймеры и их Enabled:= false, а потом просто запускал и останавливал их. Кстати я пострел Demo, погонял в пошаговом, рассмотрел всю структуру и понял, что я вроде все делал так как надо.



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

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

Наверх




Память: 0.53 MB
Время: 0.028 c
14-49303
Mr.Ice
2002-12-26 20:35
2003.01.16
Скины в делфи


1-48966
Сергей Макаров
2003-01-04 16:27
2003.01.16
Работа с ini файлами


14-49234
hatchy
2002-12-26 12:58
2003.01.16
Label................................................


3-48851
mrcat
2002-12-23 16:49
2003.01.16
Удаление данных


3-48923
danco
2002-12-18 20:07
2003.01.16
Сортировка по украинскому алфавиту