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;
Can I make a TMemo size itself to the text it contains? - Firemonkey
-
12-10-2022 - |
Question
I found that this question has been asked before for VCL, but I haven't had any luck getting the answers for that question to work on a Firemonkey TMemo
.
I've noticed that memo.Lines.Count
always seems to match the line count based off how many I add, not as they're formatted (the memo does have wordwrap turned on). Without knowing that number I'm not sure how to start figuring this out.
Any ideas?
Edit: The width of the memo will depend on the orientation of the device, obviously if the width changes the number of lines showing could change. Also, I'd like to not alter the font of the memo.
Solution
OTHER TIPS
The following function should give you what you want. It does not change anything in the memo and takes into account the font and any line breaks and wraps. If setting the memo height to the calculated value, you will need to add a few pixels for borders to eliminate scrollbars.
(add fmx.text to uses statement for XE3, might be different for other versions as they keep changing things with each release)
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;
Here's my new attempt:
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.
Hope it Helps.
This is, of course, not elegant, but you can move the caret to the end of your TMemo, and then ask for the 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;