delphicanvasgraphicscontrolsfiremonkey

Delphi textlayout.textwidth and textheight not working, why?


I'm trying to learn how to use TTextLayout object to add some special characters to my graphic drawings. Unfortunately this object seems having some special behaviours that seem not documented in Delphi help docs and on Embarcadero online docs. I have derived the following code from the Delphi code examples adding some features that I need to use. Teese features are the usage of TextWidth and TextHeight to obtain the width and height of the characters to be drawn. For convenience I have replaced the font I'm using with the Arial font. I have added some buttons to enlarge/reduce the size of the character, and some other buttons to choose different characters. Well, when the character changes, and when the size changes, nothing seems to change in width and height of the TTextLayout object. The values of width and height of the object seem remain the same. I have tried whatever came to my mind, putting before or after each single statement, but nothing. The Width and Height of the TTextLayout seem remain the same. What I'm doing wrong? What is it that I'm not understanding correctly? Thankyou for your kind help, as usual.

unit MainGraphicText;
interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.StdCtrls, FMX.Controls.Presentation, FMX.Objects,FMX.TextLayout, FMX.Edit;

type
  TMainFormGraphicText = class(TForm)
    Image1: TImage;
    Width: TEdit;
    Height: TEdit;
    DimLess: TButton;
    Label1: TLabel;
    DimMore: TButton;
    Label2: TLabel;
    ShowDim: TEdit;
    ShowChar: TEdit;
    CharLess: TButton;
    CharMore: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Image1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
    procedure DimLessClick(Sender: TObject);
    procedure DimMoreClick(Sender: TObject);
    procedure CharLessClick(Sender: TObject);
    procedure CharMoreClick(Sender: TObject);
  private
    { Private declarations }
  public
     WhichChar : Integer;
     Dimension : Single;
     MyRect : TRectF;
  end;

var
  MainFormGraphicText: TMainFormGraphicText;

implementation

{$R *.fmx}


procedure TMainFormGraphicText.CharMoreClick(Sender: TObject);
begin
   WhichChar := WhichChar + 1;
   if WhichChar > 80 then
      WhichChar := 80;
   ShowChar.Text := WhichChar.ToString;
   Image1.Repaint;
end;

procedure TMainFormGraphicText.CharLessClick(Sender: TObject);
begin
   WhichChar := WhichChar - 1;
   if WhichChar < 1 then
      WhichChar := 1;
   ShowChar.Text := WhichChar.ToString;
   Image1.Repaint;
end;

procedure TMainFormGraphicText.DimLessClick(Sender: TObject);
begin
   Dimension := Dimension - 1;
   if Dimension < 9 then
      Dimension := 9;
   ShowDim.Text := Dimension.ToString;
   Image1.Repaint;
end;

procedure TMainFormGraphicText.DimMoreClick(Sender: TObject);
begin
   Dimension := Dimension + 1;
   if Dimension > 72 then
      Dimension := 72;
   ShowDim.Text := Dimension.ToString;
   Image1.Repaint;
end;

procedure TMainFormGraphicText.FormCreate(Sender: TObject);
begin
   WhichChar := 40;
   Dimension := 48;
   MyRect := TRect.Create(TPoint.Create(0, 0),Trunc(Image1.Width),Trunc(Image1.Height));
   Canvas.BeginScene;
   Canvas.Stroke.Kind := TBrushKind.Solid;
   Canvas.Stroke.Color := TAlphaColorRec.Black;
   Canvas.Stroke.Thickness := 1.0;
   Canvas.DrawRect(MyRect,1);
   Canvas.EndScene;
end;

procedure TMainFormGraphicText.Image1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
Const Acapo = '#13#10';
var
  WPosition: Integer;
  W,H : Single;
  MyLayout: TTextLayout;
begin

  Canvas.BeginScene;
  Canvas.Stroke.Kind := TBrushKind.Solid;
  Canvas.Stroke.Color := TAlphaColorRec.Black;
  Canvas.Stroke.Thickness := 1.0;
  Canvas.DrawRect(MyRect,1);
  Canvas.EndScene;
  MyLayout := TTextLayoutManager.DefaultTextLayout.Create;
  MyLayout.BeginUpdate;
  MyLayout.TopLeft := TPointF.Create(0, 0);
  MyLayout.Font.Family := 'Arial'; // 'Delfos2';
  MyLayout.Font.Size := Dimension;
  MyLayout.Font.Style := [];
  MyLayout.Trimming := TTextTrimming.Character;
  MyLayout.Text := chr(63 + WhichChar); // Copy(Aspetti_Delfos2,WhichChar,1);
  MyLayout.Color := TAlphaColorRec.Brown;
  ShowDim.Text := MyLayout.Font.Size.ToString;
  ShowChar.Text := WhichChar.ToString;
  WPosition := MyLayout.PositionAtPoint(TPointF.Create(0, 0));
  Width.Text := MyLayout.TextWidth.ToString;
  Height.Text := MyLayout.TextHeight.ToString;
  MyLayout.EndUpdate;
  MyLayout.RenderLayout(Canvas);
  MyLayout.Free;
end;
end.

@SilverWarrior: I have tried the modifications you have proposed, but it seems they're not working at all. Particularly, I tried what follows:

  MyLayout.EndUpdate;
  MyLayout.RenderLayout(Canvas);

   Width.Text := MyLayout.TextWidth.ToString;
  Height.Text := MyLayout.TextHeight.ToString;

Logics say that only after the rendition of MyLayout the object knows the data of the changed text, but it is not. The data inside the two TEdit shows the same value than before.


Solution

  • The fact of seeing updates only in case of INVALIDATION made me think. What if the problem was limited only to updating the video fields but the true dimension values were updated correctly? I added saving the dimensional values in memory and highlighted them when exiting the program to see if that was true and it is. The various text dimension values are updated. Only the value in TEdit fields is not. To update these values you need to call INVALIDATE, but not to know the true value of the TTextLayout dimensions, which are updated correctly.