Can I make my own TMemo size for the text it contains? - firemonkey

I found that this question was asked earlier for VCL, but I could not get answers to this question for working with Firemonkey TMemo.

I noticed that it memo.Lines.Countalways matches the number of lines based on how much I add, and not how they are formatted (the note has wordwrap included). Not knowing this number, I'm not sure how to begin to understand this.

Any ideas?

Edit: the width of the note will depend on the orientation of the device, obviously, if the width changes the number of displayed lines, this can change. In addition, I would not want to change the font of the note.

+3
source share
4 answers
Procedure ResizeMemo(AMemo: TMemo);
const
  Offset = 4; //The diference between ContentBounds and ContentLayout
begin
  AMemo.Height := AMemo.ContentBounds.Height + Offset;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ResizeMemo(Memo1);
end;
+4

:

FMX:

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 305
  ClientWidth = 333
  FormFactor.Width = 1920
  FormFactor.Height = 1080
  FormFactor.Devices = [dkDesktop]
  DesignerMobile = False
  DesignerWidth = 0
  DesignerHeight = 0
  DesignerDeviceName = ''
  DesignerOrientation = 0
  DesignerOSVersion = ''
  object Memo1: TMemo
    Touch.InteractiveGestures = [igPan, igLongTap, igDoubleTap]
    Anchors = [akLeft, akTop, akRight]
    Height = 257.000000000000000000
    Position.X = 8.000000000000000000
    Position.Y = 8.000000000000000000
    TabOrder = 0
    Width = 312.000000000000000000
    Lines.Strings = (

        'Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 L' +
        'ine 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 '
      'Line 2 Line 2 Line 2 Line 2 Line 2 '
      ''
      'Line 4'

        'Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 L' +
        'ine 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Li' +
        'ne 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Line 5 Lin' +
        'e 5 Line 5 Line 5 Line 5 Line 5 ')
    Font.Family = 'Arial'
    WordWrap = True
  end
  object Button1: TButton
    Anchors = [akLeft, akTop, akRight]
    Height = 22.000000000000000000
    Position.X = 8.000000000000000000
    Position.Y = 272.000000000000000000
    TabOrder = 1
    Text = 'Show Line Count'
    Width = 312.000000000000000000
    OnClick = Button1Click
  end
  object Memo3: TMemo
    Touch.InteractiveGestures = [igPan, igLongTap, igDoubleTap]
    Height = 50.000000000000000000
    Position.X = 176.000000000000000000
    Position.Y = 184.000000000000000000
    TabOrder = 2
    Visible = False
    Width = 100.000000000000000000
    Lines.Strings = (
      '1')
  end
end

PAS:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Layouts,
  FMX.Memo, FMX.Text, FMX.StdCtrls, FMX.TextLayout;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Memo3: TMemo;
    procedure Button1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
    layout: TTextLayout;
    cont, LineHeight : real;
begin
  cont := 0;
  layout:= TTextLayout(memo3.Lines.Objects[0]);
  LineHeight := layout.TextHeight;
  for i:= 0 to memo1.Lines.Count-1 do
  begin
    layout:= TTextLayout(memo1.Lines.Objects[i]);
    if Assigned(layout) then
    begin
      cont := cont + (layout.TextHeight / LineHeight);
    end;
  end;
  showmessage('Line count according to firemonkey: ' + inttostr(memo1.Lines.Count));
  showmessage('Real line count: ' + VarToStr(cont));
end;

end.

, .

+1

This, of course, is not elegant, but you can move the carriage to the end of your TMemo and then ask CaretPosition:

function getLastMemoLineNumber(const memo: TMemo): Integer;
var
    oldCaretPosition: TCaretPosition;
begin
    Assert( Assigned(memo) );
    oldCaretPosition := memo.CaretPosition;

    try
        memo.GoToTextEnd();
        Result := memo.CaretPosition.Line;
    finally
        memo.CaretPosition := oldCaretPosition;
    end;
end;
0
source

The next function should give you what you want. This does not change anything in the note and takes into account the font and any line breaks and snippets. If you set the height of the labels for the calculated value, you will need to add a few pixels for the borders to exclude the scroll bars.

(add fmx.text expression to use for XE3, may be different for other versions as they continue to change things with each version)

function get_memo_height(amemo:tmemo):single;

var i:integer;
    astring:string;
    layout:ttextlayout;

begin
  Layout := TTextLayoutManager.DefaultTextLayout.Create;
  astring:='';
  for i:=0 to amemo.lines.count-1 do astring:=astring+amemo.lines[i]+chr(10);
  Layout.BeginUpdate;
  Layout.Text :=astring;
  Layout.WordWrap := amemo.wordwrap;
  Layout.HorizontalAlign := amemo.TextAlign;
  Layout.MaxSize := PointF(amemo.width-amemo.VScrollBar.width,maxint);
  Layout.VerticalAlign := tTextAlign.taLeading;
  Layout.Font := amemo.Font;
  Layout.TopLeft := pointf(0,0);
  Layout.EndUpdate;
  result:=layout.textrect.bottom;
  Layout.free;
end;
0
source

All Articles