Delphi 绘图到FireMonkey TControl.Canvas输出到TForm Canvas

Delphi 绘图到FireMonkey TControl.Canvas输出到TForm Canvas,delphi,firemonkey,tcanvas,Delphi,Firemonkey,Tcanvas,我刚刚开始将一个庞大的代码库转换为FireMonkey,但我遇到了一些困难 有一件事让我大吃一惊,那就是TControl.Canvas出现了一个大问题。如果调用不正确,则绘制到TCanvas,实际上绘制到窗体画布(具体来说,它在窗体上绘制为0,0,而不是自定义控件的客户端原点) 例如,在MouseMove事件中,我需要绘制一个选择。下面是一些示例代码: procedure TMyCustomControl.MouseMove(Shift: TShiftState; sX, sY: Single)

我刚刚开始将一个庞大的代码库转换为FireMonkey,但我遇到了一些困难

有一件事让我大吃一惊,那就是TControl.Canvas出现了一个大问题。如果调用不正确,则绘制到TCanvas,实际上绘制到窗体画布(具体来说,它在窗体上绘制为0,0,而不是自定义控件的客户端原点)

例如,在MouseMove事件中,我需要绘制一个选择。下面是一些示例代码:

procedure TMyCustomControl.MouseMove(Shift: TShiftState; sX, sY: Single);
begin
  inherited;

  ...
  Paint();
end;

procedure TMyCustomControl.Paint();
begin
  PaintToCanvas(Canvas);
end; 
在FireMonkey中使用此代码,可以对表单进行绘制(即表单上0,0处的输出)

如果我将MouseMove中的代码更改为Repaint();然后它正确地绘制到我的控制

显然,对于FMX,我需要触发控件的实际绘制(不仅仅是直接绘制),否则画布无效

我需要的是解释为什么它会这样工作。我的代码中有很多画布,所以我需要理解这一点,以便找出其他不兼容的代码


系统:Delphi 10.3 Rio、32或64位Windows应用程序。

您不应该在重写的
Paint()之外直接绘制,甚至不应该在VCL中。如果某个操作需要重新绘制,则应该
Invalidate()
repaint()
控件,并让操作系统向控件发出信号,使其实际绘制()。这是对VCL和FMX的尝试。@Remy:我同意,但这主要是继承的代码,一直“正常工作”,所以我尽量不使用它。问题在于FMX画布不会以任何可预测的方式出现故障。如果canvas属性不是“有效”的,为什么不直接返回nil呢?这将使这些问题更容易发现。我可以添加一些防御性代码块,如:如果Canvas.BeginSceneCount=0,则引发Exception.create('Invalid Canvas');