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

Firemonkey中TImage绘制图形后短暂消失的问题排查

Firemonkey TCanvas绘制图形短暂显示后消失的问题

在Firemonkey窗体上放置多个已绑定位图的TImage,显示正常。新增空TImage后,通过Canvas绘制图形,仅能短暂看到图形,很快就被窗体背景覆盖消失。代码可运行,但图形仅显示约十分之一秒,在FormShow事件中调用DrawBaseModel过程,相关代码如下:

Procedure NDrawCircles(var IMGTarget: TImage; xc, yc, Radius: Integer; MyPen: MyPenType);
var
   MyRect: TRectF;
   CustPattern: Array [0 .. 7] of Single;
   i: Integer;
   MyDash, bsc : Integer;
   x1, y1, x2, y2 : Extended;
   V: Single;
Begin
   bsc := IMGTarget.Canvas.BeginSceneCount;
   if bsc = 0 then
      IMGTarget.Canvas.BeginScene;
   IMGTarget.Canvas.Stroke.Kind := TBrushKind.Solid;
   IMGTarget.Canvas.Stroke.Color := MyPen.Color;
   IMGTarget.Canvas.Stroke.Thickness := MyPen.Thickness;
   IMGTarget.Canvas.Stroke.Dash := MyPen.Dash;

   x1 := xc - Radius;
   y1 := yc - Radius;
   x2 := xc + Radius;
   y2 := yc + Radius;
   MyRect := TRectF.Create(x1, y1, x2, y2);
   bsc := IMGTarget.Canvas.BeginSceneCount;
   IMGTarget.Canvas.DrawEllipse(MyRect, MyPen.Opacita);
   bsc := IMGTarget.Canvas.BeginSceneCount;
   if bsc > 0 then
      IMGTarget.Canvas.EndScene;
end;

Procedure TConfiguraDignita.DrawBaseModel;
Type
   TCircleso = Record
        XC,YC : Single;
        R : Integer;
       MyPen : MyPenType;
   end;
Var i : Integer;
    Circles : Array[1..7] of TCircleso;
Begin
   for i := 1 to 7 do
   begin
      Circles[i].XC := TargetIMG.Width / 2;
      Circles[i].YC := TargetIMG.Height / 2;
      Circles[i].MyPen.Kind := TBrushKind.Solid;
      Circles[i].MyPen.Color := claBisque;
      Circles[i].MyPen.Dash := 1;
      Circles[i].MyPen.Opacita := 1.0;
   end;
   Circles[1].MyPen.Thickness := 4.0;
   Circles[2].MyPen.Thickness := 4.0;
   Circles[3].MyPen.Thickness := 4.0;
   Circles[4].MyPen.Thickness := 2.0;
   Circles[5].MyPen.Thickness := 2.0;
   Circles[6].MyPen.Thickness := 2.0;
   Circles[7].MyPen.Thickness := 2.0;

   Circles[1].R := 600;
   Circles[2].R := 550;
   Circles[3].R := 500;
   Circles[4].R := 450;
   Circles[5].R := 400;
   Circles[6].R := 350;

   For i := 1 to 7 do
      NDrawCircles(TargetIMG, Trunc(Circles[i].XC), Trunc(Circles[i].YC), Circles[i].R, Circles[i].MyPen);

   TargetIMG.Repaint;

End;

问题根源

  • BeginScene/EndScene管理混乱:NDrawCircles中每次调用都独立处理BeginScene和EndScene,循环调用7次时,第一次开启BeginScene后,后续调用不会再开启,但每次都会执行EndScene,导致第一次EndScene就结束了绘制上下文,后续绘制无效,最终内容未正确保留。
  • 未持久化绘制内容:空TImage未绑定Bitmap,Canvas绘制的内容是临时的,窗体重绘时会被清除,因为Firemonkey默认不会自动保存临时Canvas的绘制结果。
  • Repaint调用错误:DrawBaseModel末尾的TargetIMG.Repaint会触发控件重绘,此时临时绘制已结束,反而导致TImage清空显示空白。

修复方案

1. 为TImage绑定Bitmap并统一管理绘制上下文

确保绘制内容持久化到Bitmap中,且由外部统一控制BeginScene和EndScene:

Procedure TConfiguraDignita.DrawBaseModel;
Type
   TCircleso = Record
        XC,YC : Single;
        R : Integer;
       MyPen : MyPenType;
   end;
Var i : Integer;
    Circles : Array[1..7] of TCircleso;
Begin
   // 初始化Bitmap,确保尺寸与TImage一致
   if TargetIMG.Bitmap = nil then
      TargetIMG.Bitmap := TBitmap.Create;
   TargetIMG.Bitmap.SetSize(TargetIMG.Width, TargetIMG.Height);

   // 初始化Circles的原有代码保留
   for i := 1 to 7 do
   begin
      Circles[i].XC := TargetIMG.Width / 2;
      Circles[i].YC := TargetIMG.Height / 2;
      Circles[i].MyPen.Kind := TBrushKind.Solid;
      Circles[i].MyPen.Color := claBisque;
      Circles[i].MyPen.Dash := 1;
      Circles[i].MyPen.Opacita := 1.0;
   end;
   Circles[1].MyPen.Thickness := 4.0;
   Circles[2].MyPen.Thickness := 4.0;
   Circles[3].MyPen.Thickness := 4.0;
   Circles[4].MyPen.Thickness := 2.0;
   Circles[5].MyPen.Thickness := 2.0;
   Circles[6].MyPen.Thickness := 2.0;
   Circles[7].MyPen.Thickness := 2.0;

   Circles[1].R := 600;
   Circles[2].R := 550;
   Circles[3].R := 500;
   Circles[4].R := 450;
   Circles[5].R := 400;
   Circles[6].R := 350;

   // 统一开启和结束绘制上下文
   TargetIMG.Bitmap.Canvas.BeginScene;
   try
      For i := 1 to 7 do
         NDrawCircles(TargetIMG, Trunc(Circles[i].XC), Trunc(Circles[i].YC), Circles[i].R, Circles[i].MyPen);
   finally
      TargetIMG.Bitmap.Canvas.EndScene;
   end;

   // 无需调用Repaint,Bitmap更新后会自动触发重绘
End;

2. 修改NDrawCircles方法,直接操作Bitmap的Canvas

去掉方法内的BeginScene/EndScene逻辑,避免嵌套错误:

Procedure NDrawCircles(var IMGTarget: TImage; xc, yc, Radius: Integer; MyPen: MyPenType);
var
   MyRect: TRectF;
   x1, y1, x2, y2 : Extended;
Begin
   with IMGTarget.Bitmap.Canvas do
   begin
      Stroke.Kind := TBrushKind.Solid;
      Stroke.Color := MyPen.Color;
      Stroke.Thickness := MyPen.Thickness;
      Stroke.Dash := MyPen.Dash;

      x1 := xc - Radius;
      y1 := yc - Radius;
      x2 := xc + Radius;
      y2 := yc + Radius;
      MyRect := TRectF.Create(x1, y1, x2, y2);
      DrawEllipse(MyRect, MyPen.Opacita);
   end;
end;

3. 调整绘制时机

建议在FormCreate或TargetIMG.OnResize事件中调用DrawBaseModel,确保TImage尺寸已确定。若必须在FormShow调用,需等待窗体完成布局后执行(比如加个短延迟或在FormActivate中调用)。

内容的提问来源于stack exchange,提问作者Sergio Bonfiglio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 02:07:28