Delphi FMX中Form动画正常,Image组件动画仅显示最终状态
问题:FMX中Image组件内无法显示圆形移动过程,Form上却正常
我用Delphi的FMX.Graphics实现了圆形在Form上沿X轴移动的功能,代码运行正常;但把逻辑移到Form的Image1组件内时,只能看到圆形的最终位置,看不到移动过程。
Form上正常运行的代码
procedure TForm1.ButtonMoveFormClick(Sender: TObject); var MyRect: TRectF; n: integer; begin for n := 1 to 100 do begin // sets the circumscribed rectangle of the ellipse MyRect := TRectF.Create(n, 0, n+200, 200); // draws the ellipse on the canvas Form1.Canvas.BeginScene; Form1.Canvas.Clear(TAlphaColors.White); Form1.Canvas.DrawEllipse(MyRect, 40); Form1.Canvas.FillEllipse(MyRect,50); Form1.Canvas.EndScene; sleep(10); end; end;
Image组件上仅显示最终位置的代码
procedure TForm1.Button_Move_PictureClick(Sender: TObject); var MyRect: TRectF; n: integer; begin // sets the size of the TBitmap Image1.Bitmap := TBitmap.Create(Round(Image1.Width), Round(Image1.Height)); for n := 1 to 100 do begin // sets the circumscribed rectangle of the ellipse MyRect := TRectF.Create(n, 0, n+200, 200); // draws the ellipse on the canvas Image1.Bitmap.Canvas.BeginScene; Image1.Bitmap.Canvas.Clear(TAlphaColors.White); Image1.Bitmap.Canvas.DrawEllipse(MyRect, 40); Image1.Bitmap.Canvas.FillEllipse(MyRect,50); Image1.Bitmap.Canvas.EndScene; sleep(10); end; beep; end;
原因分析
- Form的Canvas是即时渲染到界面的,调用
EndScene后会直接触发Form的重绘流程,所以每一步的绘制结果都能实时显示。 - Image组件的Bitmap是离线绘制缓冲区,修改Bitmap的Canvas内容后,Image不会自动触发重绘。循环过程中主线程被
Sleep阻塞,界面没有机会更新,直到循环结束,Image才会一次性展示最终的Bitmap状态,导致中间移动过程被跳过。 - 另外,Form上的代码其实也存在主线程阻塞的问题,只是因为Form的重绘机制刚好能让每一步绘制被看到,但本质上这种写法并不规范。
解决方案
方案1:强制Image实时重绘
在每次EndScene后调用Image1.Repaint,强制组件刷新界面,这样每一步的绘制结果都会显示出来:
procedure TForm1.Button_Move_PictureClick(Sender: TObject); var MyRect: TRectF; n: integer; begin // 初始化Bitmap尺寸 Image1.Bitmap := TBitmap.Create(Round(Image1.Width), Round(Image1.Height)); for n := 1 to 100 do begin MyRect := TRectF.Create(n, 0, n+200, 200); Image1.Bitmap.Canvas.BeginScene; Image1.Bitmap.Canvas.Clear(TAlphaColors.White); Image1.Bitmap.Canvas.DrawEllipse(MyRect, 40); Image1.Bitmap.Canvas.FillEllipse(MyRect,50); Image1.Bitmap.Canvas.EndScene; // 强制Image刷新界面 Image1.Repaint; Sleep(10); end; Beep; end;
方案2:使用Timer实现非阻塞动画(推荐)
用TTimer代替循环+Sleep,避免阻塞主线程,同时保证界面流畅响应:
// 在Form的私有字段中添加位置变量 private FPosition: Integer; procedure TForm1.FormCreate(Sender: TObject); begin FPosition := 1; // 初始化Bitmap尺寸 Image1.Bitmap := TBitmap.Create(Round(Image1.Width), Round(Image1.Height)); Timer1.Interval := 10; Timer1.Enabled := False; end; procedure TForm1.Button_Move_PictureClick(Sender: TObject); begin // 重置位置并启动Timer FPosition := 1; Timer1.Enabled := True; end; procedure TForm1.Timer1Timer(Sender: TObject); var MyRect: TRectF; begin if FPosition > 100 then begin Timer1.Enabled := False; Beep; Exit; end; MyRect := TRectF.Create(FPosition, 0, FPosition+200, 200); Image1.Bitmap.Canvas.BeginScene; Image1.Bitmap.Canvas.Clear(TAlphaColors.White); Image1.Bitmap.Canvas.DrawEllipse(MyRect, 40); Image1.Bitmap.Canvas.FillEllipse(MyRect,50); Image1.Bitmap.Canvas.EndScene; Image1.Repaint; Inc(FPosition); end;
内容的提问来源于stack exchange,提问作者Valeriy
相关产品推荐
相关产品推荐

