You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:57:35