多线程动画问题(屏幕花屏)300大元(300分)

  • 主题发起人 主题发起人 大文
  • 开始时间 开始时间

大文

Unregistered / Unconfirmed
GUEST, unregistred user!
本人用一个TIMAGE装入一个图片,然后用代码动态更改该IMAGE的位置从而实现动画的效果(将图片在屏幕上移动即可),动画是出来可问题也来了。
问题:用普通代码作动画完全正常,改在多线程中就出现花屏了,除了调用的方式不同其他完全一样!
求解:还是以TIMAGE基础如何排除此问题(请别建议让我将TIMAGE放在TPANEL之类的方式,因为我自己已经实现了)。

代码如下:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Buttons, Mask;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Image1: TImage;
Image2: TImage;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);

private
{ Private declarations }

public
{ Public declarations }
end;

tthread1=class(tthread)
public
caller:Tcustomform;
img:TComponent;
constructor create(ACaller:tcustomform;Aimg:TComponent=nil);
destructor destroy;override;
procedure execute;override;
end;

procedure tdemo(caller:tcustomform;img:TComponent=nil);

var
Form1: TForm1;

implementation

{$R *.dfm}

{ thread1 }
procedure tdemo(caller:tcustomform;img:TComponent=nil);
var i:integer;
begin
i:=0;
while i<caller.Width -50 do //将图片从左至右慢慢移动
begin
TImage(img).left :=i; //更改图片的位置
sleep(10);
i:=i+4;
end;
end;

constructor tthread1.create(ACaller:tcustomform;Aimg:TComponent=nil);
begin
inherited create(true);
Caller:=ACaller; //form
img:=Aimg; //image object
FreeOnTerminate :=true;
resume;
end;

destructor tthread1.destroy;
begin
inherited;
end;

procedure tthread1.execute;
begin
tdemo(caller,img); //在线程中调用例子
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
tthread1.create(self,image1); //用线程调用例子(出现花屏)
tthread1.create(self,image2);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
tdemo(Self,image1); //直接调用例子(正常)
tdemo(Self,image2);
end;

end.
 
>>tdemo(Self,image1);
是個過程方法的調用, 與線程無關, 所以正常
>>tthread1.create(self,image1);
在線程中調用, 沒有使用同步來更新, 所以會有問題!
 
to Aiirii:
如何同步,用Synchronize吗,如果用用该方法则屏幕上的多个图像不能同时动作,所以不可取。
我查过代码,只要有canvas操作的对象基本上有此问题,如TLABEL,TEDIT,TMEMO等,只有TBUTTON,TPANEL等少数几个类型不会出现花屏,所以我将TIMAGE放在TPANEL对象上就可以了,可是其他问题又出来了。

难道DELPHI连这么简单的问题都没有考虑到?
 
看看这两个帖子:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1993353
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2016628
 
to thx1180:
你的意思是让我把图像处理的部分代码放在 WndProc 中完成,还有其他更好的方法否?
 
我的意思是线程只是起一个定时的作用,定时发送消息让主线程处理即可,这是处理你这类问题比较好的线程同步方法吧。
 
我还是贴一段代码吧:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
HyTimer, jpeg;

type
TForm1 = class(TForm)
HyTimer1: THyTimer;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure HyTimer1Timer(Sender: TObject);
private
FImgA: TJPEGImage;
FImgB: TJPEGImage;
TempBmp: TBitmap;
FPos: Integer;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure LoadAImage(AFile: string; A: TJPEGImage);
var
MS: TMemoryStream;
begin
if not FileExists(AFile) then Exit;
ms := TMemoryStream.Create;
try
ms.LoadFromFile(AFile);
A.LoadFromStream(ms);
finally
ms.Free;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FImgA := TJPEGImage.Create;
FImgB := TJPEGImage.Create;
LoadAImage('D:/Photo/32pic02.jpg', FImgA);
LoadAImage('D:/Photo/mm_blur.jpg', FImgB);
TempBmp := TBitmap.Create;
FPos := 0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
TempBmp.Free;
FImgB.Free;
FImgA.Free;
end;

procedure TForm1.HyTimer1Timer(Sender: TObject);
var
ARect: TRect;
begin
ARect := ClientRect;
TempBmp.Width := Width;
TempBmp.Height := Height;
TempBmp.Canvas.Brush.Color := Color;
TempBmp.Canvas.FillRect(ARect);
TempBmp.Canvas.Draw(FPos, 0, FImgA);
TempBmp.Canvas.Draw(FPos, 20, FImgB);
Canvas.Draw(0, 0, TempBmp);
Inc(FPos);
if FPos > Width then FPos := 0;
end;

end.

其中THyTimer是线程定时器,可以用普通定时器替换。
 
THyTimer:
你的提议有点意思,应该对我有所启发。
 
所有涉及到可视VCL的操作,建议用Synchronize。

如果是对TCanvas操作,请用Lock和Unlock方法。

不是DELPHI没有考虑到,而是多线程应用中数据访问需要保护是一个常识。

以下是广告时间^_^
推荐偶这篇文章:
http://www.csdn.net/develop/Read_Article.asp?Id=22466
 
to 猛禽:
>>所有涉及到可视VCL的操作,建议用Synchronize。
如果用Synchronize同一时间只能有一个动画可以更新(当然不排除是我的代码有毛病)

>>如果是对TCanvas操作,请用Lock和Unlock方法。
强行用lock和unlock容易导致死锁,我随便试了一下就死了。

>>不是DELPHI没有考虑到,而是多线程应用中数据访问需要保护是一个常识。
Delphi手册上说,基于图形的VCL调用基本上是安全的,用户不需要考虑线程安全。

那篇多线程文章写的不错,佩服!
 
>>Delphi手册上说,基于图形的VCL调用基本上是安全的,用户不需要考虑线程安全。
有點懷疑

>>如果用Synchronize同一时间只能有一个动画可以更新(当然不排除是我的代码有毛病)
可否寫到同一線程, 同時處理多個動畫???
 
Aiirii:
我的程序中几乎所有对象都是动态创建的,对象中有单独的线程处理图形动画,所以不适合集中处理。
 
我覺得, 如果同時更新, 不加同步, 肯定會有問題的, 而如用Synchronize會比較耗時的話, 那, 可考慮下互斥量, 這樣, 可能用戶就感覺不到同步帶來的延时了,但又可保证不会冲突!
 
建议使用SWF,来演示各种动画效果。
 
让主线程处理比较好
 
Aiirii:可以考虑,但工作量大;
w128:画面是动态产生的,不能用flash来做;
wfzha:由于对象是动态产生的,在主线程中处理需要设置大量的代码,不太合适;
 
Double Buffer之类恐怕是最基础的东西了。 记得我学Delphi时看的技巧
第一篇就是“如何用Double Buffer实现动画”。
 
Town:
启用 Double Buffer后巨慢,不可取。
 
用线程移动Timage控件?那应该Synchronize吧,不过这样还不如用timer去控制呢。
如果不Synchronize出问题也是正常的
 
后退
顶部