在线程里用Bitmap载入图片,并在PaintBox上画出来。
开始的时候可以正常显示,但运行一会儿后PaintBox就不更新了。当拖动滚动条(PaintBox大于窗口),或者放大缩小(PaintBox跟随变化),甚至什么都不动有时候也会出现这样的状况。
在线程里设断点可知线程仍在正常运行,载入的图片也是正确的。代码大至如下:
procedure TFrameThread.Execute;
begin
while not Terminated do
begin
Inc(i);
FBitmap.LoadFromFile(IntToStr(i) + '.bmp');
with Form1.PaintBox1 do
try
Canvas.Lock;
Canvas.StretchDraw(Rect(0, 0, Width, Height), FBitmap);
finally
Canvas.Unlock;
end;
Sleep(100);
end;
end;
开始的时候可以正常显示,但运行一会儿后PaintBox就不更新了。当拖动滚动条(PaintBox大于窗口),或者放大缩小(PaintBox跟随变化),甚至什么都不动有时候也会出现这样的状况。
在线程里设断点可知线程仍在正常运行,载入的图片也是正确的。代码大至如下:
procedure TFrameThread.Execute;
begin
while not Terminated do
begin
Inc(i);
FBitmap.LoadFromFile(IntToStr(i) + '.bmp');
with Form1.PaintBox1 do
try
Canvas.Lock;
Canvas.StretchDraw(Rect(0, 0, Width, Height), FBitmap);
finally
Canvas.Unlock;
end;
Sleep(100);
end;
end;
begin
FreeOnTerminate := True;
Synchronize(dosomething);
end;procedure TMyThread.dosomething;
begin
Inc(i);
FBitmap.LoadFromFile(IntToStr(i) + '.bmp');
...
end;
Canvas.Lock;
Canvas.StretchDraw(Rect(0, 0, Width, Height), FBitmap);
finally
Canvas.Unlock;
sleep(0); // <- 加个进去试试
end;
Sleep(100);
后边加个 Invalidate 刷新试下
可以利用Synchronize
也可以使用临界区
如果多个线程100ms刷新一幅图,是可能有些图没看到就被覆盖了感觉多线程提供图片文件名,覆盖到一个string;主线程用定时器取这个变量来刷新
比较好
如果刷新慢、卡,那用户只会看到b,没机会看到a曾经显示过
所以,不如直接用a、b的文件名来更新,定时器来真正显示不过,如果你只有一个工作线程,而且有100ms的显示时间,应该不会看不到a的
正因为定时器不是多线程,所以,显示图片这样容易与主线程冲突的工作,由定时器做更保险
工作线程不用涉及图片加载,只负责告诉主线程的定时器,现在该加载什么文件
定时器判断目前需要加载的图片文件名是不是已经就绪,是则加载之并把文件名变量清空,否则什么也不干
这样,定时器的间隔可以设的很短,如10ms
定时事件:
begin
timer1.enabled:=false;
if imgfilename<>'' then
begin
FBitmap.LoadFromFile(IntToStr(i) + '.bmp');
with Form1.PaintBox1 do
Canvas.StretchDraw(Rect(0, 0, Width, Height), FBitmap);
imgfilename:='';
end;
timer1.enabled:=true;
end;线程:
procedure TFrameThread.Execute;
begin
while not Terminated do
begin
Inc(i);
imgfilename:=IntToStr(i) + '.bmp';
Sleep(100);
end;
end;
程序这二天没有出错,暂时不改了。哪位有兴趣讨论一下:所有的代码都执行了,为什么会不显示呢?Windows在什么情况下会不刷新窗口?主程没有不响应,只是PaintBox不刷新。
只是试验。
你的代码已经写好,而且作为一个通用的准视频播放,使用主线程的定时器,不如线程、函数来的方便