When I invalidate one control on a form, then the Paint
method is called for ALL controls on that form. This happens on iOS, while on Windows the local invalidation works and only the requested control is being painted.
To verify this, I made a small test program with just two TPaintBox
on a form and assigned these Click and Paint methods to them:
procedure TForm1.PaintBox1Click(Sender: TObject);
var lPaintBox: TPaintBox;
begin
lPaintBox := TPaintBox(Sender);
lPaintBox.InvalidateRect(lPaintBox.LocalRect);
end;
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var lPaintBox: TPaintBox;
begin
lPaintBox := TPaintBox(Sender);
lPaintBox.Canvas.Fill.Color := claBlack;
lPaintBox.Canvas.FillText(RectF(0,0,50,50),'Paint count = '+inttostr(lPaintBox.Tag),true, 1, [], ttextAlign.Center);
lPaintBox.Tag := lPaintBox.Tag +1;
end;
No matter which one of the paintboxes I touch, the other one is painted too. So on iOS they always show the same number.
Is there a way to avoid this?
I use Berlin update 2 with XCode 8.2
UPDATE
Investigating this further I found that InvalidateRect calls this:
procedure TCustomForm.AddUpdateRect(R: TRectF);
begin
...
if (Canvas <> nil) and not (TCanvasStyle.SupportClipRects in Canvas.GetCanvasStyle) then
InvalidateRect(RectF(0, 0, FCanvas.Width, FCanvas.Height))
else
InvalidateRect(R);
end;
Which means if the Canvas does not support ClipRects then the full form is invalidated. Since mobile platforms always use TCanvasGPU
, I checked what it supports:
class function TCanvasGpu.GetCanvasStyle: TCanvasStyles;
begin
Result := [TCanvasStyle.NeedGPUSurface];
end;
In other words: mobile platforms does not (currently) support local invalidation and always repaints everything on the form every time any control wants to invalidate anything.
This is unfortunate when there are many and/or complex controls on a form, so could there be a workaround?