Форум: "Основная";
Текущий архив: 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