关于TTimer 控件

来源:互联网 发布:delphi是不是编程语言 编辑:程序博客网 时间:2024/06/05 17:33

近期写程序时用了TTimer控件,执行的代码如下:

var
pexe : pexetype;
i,j : integer;
url,ss : string;
begin
for i := 0 to monlist.Count - 1 do
begin
pexe := monlist[i];
if pexe.otherInfo = 0 then
continue;
url := 'http://localhost:' + inttostr(pexe.otherInfo) + '/test.php';
ss := '';
try
ss := idhttp1.Get(url);
except
sleep(1000);
if idhttp1.IOHandler <> nil then
idhttp1.IOHandler.Close;
try
ss := idhttp1.Get(url);
except
mysleep(1000);
if idhttp1.IOHandler <> nil then
idhttp1.IOHandler.Close;
try
ss := idhttp1.Get(url);
except
ss := '';
end;
end;
end;
if trim(ss) <> 'ok' then
begin
pexe.otherInfo := 0;
TMon.KillTask(pexe.pid);
log.log('killtask:'+pexe.path);
end;
end;

为了防止程序在sleep(1000)时处于假死状态,我把sleep(1000)用函数mysleep来代替,把1秒分解也10份,代码如下:

procedure mysleep(sec: integer);
var
i,j : integer;
begin
for i := 0 to sec - 1 do
begin
for j := 0 to 9 do
begin
sleep(100);
application.ProcessMessages;(让界面响应其他消息,如重画之类的,防止界面假死)
end;
end;
end;

问题就出来了,运行程序,一到mysleep(1) ,程序就不往下走了,又重新从Timer1Timer函数开始执行。为什么会这样,百思不得其解,后面看了TTimer的原码,才发现:

procedure TTimer.WndProc(var Msg: TMessage);
begin
with Msg do
if Msg = WM_TIMER then
try
Timer;
except
Application.HandleException(Self);
end
else
Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;

对delphi而言,TTimer控件实际是一个消息定时发送器,每隔一个Interval就会定时发送类似WM_TIMER 的消息,当程序分发并获取这个消息时,就会处理Timer1Timer的事件。

那么原因找到了。application.ProcessMessages;这个函数是让程序处理其他消息,这样程序又从头开始了。

包括 indy 组件里的IdAntiFreeze控件也是通过application.ProcessMessages来实现的,所以如果Timer事件里有用到indy系列控件时,可能会出问题,如idhttp控件,在timer里用了,就不能放IdAntiFreeze控件了。

一般情况下,application.ProcessMessages 这个函数尽量要少用,因为他会影响消息的处理流程。如果要防止界面出现顿卡,最好的解决方法是用多线程来实现,把耗时的工作放到其他线程里来实现,而不全用来主线程里。

原创粉丝点击