Search code examples
delphifiremonkey

Delphi Firemonkey MeasureText not working as expected


I have Delphi 10 Seattle Version 23.0.22248.5795. I am using the following code snipet

ARectF := TRectF.Create(0,0,0,0);
ABitmap.Canvas.Stroke.Kind := TBrushKind.bkSolid;
ABitmap.Canvas.StrokeThickness := 1;
ABitmap.Canvas.Fill.Color := TAlphaColors.Red;
ABitmap.Canvas.Font.Size := 18;
ABitmap.Canvas.Font.Family:='Arial';
ABitmap.Canvas.Font.Style:=[TFontStyle.fsbold];

ABitmap.Canvas.MeasureText(ARectF, Text, False, [], TTextAlign.Leading);
ARectF := TRectF.Create(0, 0, 50, 20);  //<---- needed to show, but not correct width!
ARectF.TranslateTo(BottomLeftPt); 
if ABitmap.Canvas.BeginScene then try
  DrawFilledRect(ABitmap, ARectF, BackgroundColor, BorderColor, 1, TBrushKind.Solid, 0, 0);
  ARectF.Left := ARectF.Left + 2;
  ABitmap.Canvas.FillText(ARectF, Text, False, 100, [], TTextAlign.Leading);
finally
  ABitmap.Canvas.EndScene;
end;

When I call the MeasureText function, it is not passing back ARectF with the TRectF needed to display the text. So I have to manually set up ARectF just to see anything. Notice that I set it to 0, 0, 50, 20. I want to be able to remove this line, but without it, only a single dot is shown on the screen.

I tried tracing through the Delphi code, and it seems to involve layouts, which I have not been using. I am just recently converting from VCL to FMX, and I am trying to port code. I haven't yet figured out how layouts work. And frankly, I just want to draw text on the screen.

The documentation for MeasureText() seems to indicate that ARectF is the output variable. Am I misunderstanding the purpose of this function? If so, how should I properly know how wide the text rectangle should be for handling inputs of variable length?

Can anyone help me figure out why MeasureText is not correctly setting up ARectF for me?


Solution

  • MeasureText treats the ARectF parameter as the rectangle into which the text is to be placed considering the size of the bounding rectangle and text alignments and other settings. The returned ArectF contains the actual bounding rectangle into which the text would be rendered.

    For example:

    Input value of ARectF

    ARectF := TRectF.Create(0,0,200,100);
    

    Other params as in your example

    Return value is (rounded by me)

    Left: 0
    Top: 39.7
    Right: 44.0
    Bottom: 60.3
    

    Horizontally at the left because of TTextAlign.Leading.

    Vertically at the center because of TTextAlign.Centered

    The documentation is somewhat ambiguous.