Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2003.01.16;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.009 c
1-49032
Геннадий
2003-01-07 22:26
2003.01.16
Обработка OnMouseMove для TRadioGroup - КАК ?


3-48941
Iren
2002-12-23 06:40
2003.01.16
ADO


3-48958
lefan
2002-12-23 11:40
2003.01.16
Проблема с Query....


1-49037
yankee
2003-01-07 21:26
2003.01.16
BD Emage Editor


1-49085
John
2003-01-05 01:31
2003.01.16
возв.в степень числа





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский