Delphi &引用;“对象锁未拥有”;使用OnPaint方法时出错

Delphi &引用;“对象锁未拥有”;使用OnPaint方法时出错,delphi,firemonkey,Delphi,Firemonkey,我试图用OnPaint方法绘制一个简单的图像。代码编译得很好,但当应用程序启动时,会显示“Object lock not owned”错误,而不会发生其他任何事情。你能告诉我我犯了什么错误吗?代码显示了我正在使用的OnPaint事件。谢谢大家的帮助 procedure TTabbedForm.Image1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF); var p1, p2, p3, p4, p5, p6: T

我试图用OnPaint方法绘制一个简单的图像。代码编译得很好,但当应用程序启动时,会显示“Object lock not owned”错误,而不会发生其他任何事情。你能告诉我我犯了什么错误吗?代码显示了我正在使用的OnPaint事件。谢谢大家的帮助

procedure TTabbedForm.Image1Paint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
  var
  p1, p2, p3, p4, p5, p6: TPointF;
  prst1: TRectF;
  i :Integer;
begin
 Image1.Bitmap.Canvas.Stroke.Color := TAlphaColors.Black;
 Image1.Bitmap.Canvas.Stroke.Thickness := 3;
 p1 := TPointF.Create(PX, PY);
 Image1.Bitmap.Canvas.BeginScene;
  with TabbedForm do begin
      for i := 0 to 360 do
        if (i mod 15)=0 then
        begin
         p2 := TPointF.Create(Round(PX+PP*sin(i*pi/180)), Round(PY+PP*cos(i*pi/180)));
          Image1.Bitmap.Canvas.DrawLine(p1, p2, 100);
        end;
      for i := 0 to PP do
        if (i mod 20)=0 then
        begin
        prst1 := TRectF.Create(PX+i,PY+i,PX-i,PY-i);
        Image1.Bitmap.Canvas.DrawEllipse(prst1, 100);
        end;
      for i := 0 to 400 do
        if (i mod 20)=0 then
        begin
        p3 := TPointF.Create(i,2*PP);
        p4 := TPointF.Create(i,2*PP+2*PP);
        Image1.Bitmap.Canvas.DrawLine(p3, p4, 100);
        end;
      for i := 0 to 400 do
        if (i mod 20)=0 then
        begin
        p5 := TPointF.Create(0,2*PP+i);
        p6 := TPointF.Create(2*PP+2*PP,2*PP+i);
        Image1.Bitmap.Canvas.DrawLine(p5, p6, 100);
        end;
  Image1.Bitmap.Canvas.EndScene;
  end;
 end;

我想你会收到这个错误信息,因为你在画布上画画的时候你是不被允许的。造成这种情况的潜在原因是:

  • 您正在图像的绘制事件中绘制图像的位图。图像用于显示预生成或加载的位图,由于修改位图会触发OnPaint事件,我认为从同一事件中进行这些更改是一个坏主意。它要求一个无休止的循环,或其他不必要的副作用
  • 您使用的BeginScene/EndScene不正确。只有当BeginScene返回true时,才应继续绘制。实际上,在给定的画布上绘制绘制事件时,根本不需要调用它们
  • 您(部分)使用表单的全局实例而不是当前实例(Self),这可能(取决于您的应用程序)导致在错误的实例上绘制
小免责声明:我尽可能地保留了您的代码,只是更改了我认为可能导致您出现问题的内容。我认为这些变化都是有道理的,但我必须承认我从来没有在FMX中画过很多画,所以可能其中一些有点幼稚或过度保护(或明显错误)

与您的代码相比,此代码中的内容有所不同:

  • 使用TPaintbox(您必须添加名为“Paintbox1”的TPaintbox,并将此方法添加到其OnPaint处理程序)。油漆盒用于直接绘图。如果您能够在特定事件上预渲染图像的位图,例如启动应用程序、单击按钮、定时器等,则还可以保留图像
  • 正确使用BeginScene和EndScene,使用
    if
    try..finally
    块。BeginScene是否会给您一个锁,并根据成功与否返回一个布尔值。只有在实际获得锁的情况下才能继续,在这种情况下也只能调用EndScene,因为它们是ref计数的,如果这样做错误,可能会破坏ref计数,从而导致应用程序中的所有后续绘制
  • 场景中的笔划设置也是如此。不是100%确定是否需要,但我想这也是绘制场景的一部分,对吗
  • 完全忽略
    BeginScene..EndScene
    。Paintbox或Image控件应该已经调用了它自己。看
  • 只需使用
    Canvas
    。它作为参数传递给事件处理程序,因此最好使用它,然后自己尝试找到合适的画布
  • 用删除了
    。这有点遥不可及,但看起来您引用的是一个全局
    TTabbedForm
    变量,而且由于您在TTabbedForm方法中,因此应该能够按原样使用当前实例的属性和方法,或者在遇到命名冲突时使用
    Self.
    。表单和数据模块最好不要依赖于这些全局变量,如果希望表单有多个实例,那么实际上会遇到问题,在这种情况下,您的原始代码会部分地在错误的实例上运行
程序TTabbedForm.Paintbox1Paint(
发送方:TObject;Canvas:TCanvas;const-ARect:TRectF);
变量
p1,p2,p3,p4,p5,p6:TPointF;
prst1:TRectF;
i:整数;
开始
p1:=TPointF.Create(PX,PY);
Canvas.Stroke.Color:=TAlphaColors.Black;
Canvas.Stroke.Thickness:=3;
对于i:=0到360 do
如果(i mod 15)=0,则
开始
p2:=TPointF.Create(圆形(PX+PP*sin(i*pi/180)),圆形(PY+PP*cos(i*pi/180));
帆布拉丝(p1、p2、100);
结束;
对于i:=0到PP do
如果(i mod 20)=0,则
开始
prst1:=TRectF.Create(PX+i,PY+i,PX-i,PY-i);
帆布抽屉(prst1,100);
结束;
对于i:=0到400 do
如果(i mod 20)=0,则
开始
p3:=TPointF.Create(i,2*PP);
p4:=TPointF.Create(i,2*PP+2*PP);
帆布拉丝(p3、p4、100);
结束;
对于i:=0到400 do
如果(i mod 20)=0,则
开始
p5:=TPointF.Create(0,2*PP+i);
p6:=TPointF.Create(2*PP+2*PP,2*PP+i);
帆布拉丝(p5、p6、100);
结束;
结束;

我想您会收到此错误消息,因为您在画布上绘图时,不允许这样做。造成这种情况的潜在原因是:

  • 您正在图像的绘制事件中绘制图像的位图。图像用于显示预生成或加载的位图,由于修改位图会触发OnPaint事件,我认为从同一事件中进行这些更改是一个坏主意。它要求一个无休止的循环,或其他不必要的副作用
  • 您使用的BeginScene/EndScene不正确。只有当BeginScene返回true时,才应继续绘制。实际上,在给定的画布上绘制绘制事件时,根本不需要调用它们
  • 您(部分)使用表单的全局实例而不是当前实例(Self),这可能(取决于您的应用程序)导致在错误的实例上绘制
小免责声明:我尽可能地保留了您的代码,只是更改了我认为可能导致您出现问题的内容。我认为这些变化都是有道理的,但我必须承认我从来没有在FMX中画过很多画,所以可能其中一些有点幼稚或过度保护(或明显错误)

与您的代码相比,此代码中的内容有所不同:

  • 使用TPaintbox(您必须添加名为“Paintbox1”的TPaintbox,并将此方法添加到其OnPaint处理程序)。油漆盒用于直接绘图。如果能够预渲染,也可以保留图像
    procedure TTabbedForm.Button1Click(Sender: TObject);
    var
      p1, p2, p3, p4, p5, p6: TPointF;
      prst1: TRectF;
      i: integer;
    begin
      Image1.Bitmap.SetSize(300, 300); // must be set before call to BeginScene
      if Image1.Bitmap.Canvas.BeginScene then
      try
        Image1.Bitmap.Canvas.Stroke.Color := TAlphaColors.Black;
        Image1.Bitmap.Canvas.Stroke.Thickness := 1;
        p1 := TPointF.Create(px, py);
    
        for i := 0 to 360 do
          if (i mod 15) = 0 then
          begin
            pp := i;
            p2 := TPointF.Create(Round(px + pp * sin(i * pi / 180)),
              Round(py + pp * cos(i * pi / 180)));
            Image1.Bitmap.Canvas.DrawLine(p1, p2, 100);
          end;
    
        for i := 0 to pp do
        ...
    
        for i := 0 to 400 do
        ...
    
        for i := 0 to 400 do
        ....
    
      finally
        Image1.Bitmap.Canvas.EndScene;
      end;
    end;