0

here is my sample code in Firemonkey;

var
   f: integer; 
   Label1: TLabel;
   MyStringArray: TArray<String>;
   Panel1: TPanel;
   Layout1: TLayout;
begin
   Layout1.Align := TAlignLayout.Client;
   MyStringArray := ['aa','bb','cc','dd','ee','ff'];
   f:= 10;
   Layout1.BeginUpdate;
   for i := 0 to length(MyStringArray) - 1 do
   begin
        Label1 := TLabel.Create(Self);
        Label1.Name := 'Label' + i.ToString;
        Label1.Text := 'Label_' + MyStringArray[i];
        Label1.Position.Y := f;
        Label1.Align := TAlignLayout.Top;
        Label1.Parent := Layout1;
        inc(f, 15);
   end;
   Layout1.EndUpdate;
end; 

MyStringArray is a dynamic array no always with the same number of elements, so I resize a TPanel (Panel1) with the contents of TLayout (Layout1) according with number of labels;

Panel1.Height := Layout1.ChildrenRect.Height

This works fine when the number of labels grows in Layout1, but when the number of labels is less, Layout1.ChildrenRect.Height has no effect and not shrinks it, height of the Layout1 always keeps the higher value.

Is there any solution or any other alternative to how to do it?, thanks Regards.

Juande
  • 73
  • 1
  • 10
  • Are you saying the ChildrenRect is wrong after you free/remove controls? If so how are you freeing them and on what platform? – Mike Sutton Feb 14 '15 at 19:00
  • Hello Mike, I free/remove controls using `Layout1.DeleteChildren` everytime before to call `Layout1.ChildrenRect.Height`, tested on Windows and Android. – Juande Feb 14 '15 at 20:20

2 Answers2

2

I hope that this code will help in that. I apologize for more editing, this is last, but I was trying again and the code was not entirely correct.

type
  TControlHelper = class helper for TControl
  public
    function ChildrenWidth: Single; 
    function ChildrenHeight: Single; 
  end;

function TControlHelper.ChildrenWidth: Single;
var
  VIndex: Integer;
  VControl: TControl;
  VRect: TRectF;
begin
  VRect := TRectF.Empty;
  if not ( ClipChildren or SmallSizeControl ) and ( Controls <> nil ) then
  begin
    for VIndex := GetFirstVisibleObjectIndex to GetLastVisibleObjectIndex - 1 do
    begin
      VControl := Controls[ VIndex ];
      if VControl.Visible then
        VRect := UnionRect( VRect, VControl.Margins.MarginRect( TRectF.Create( VControl.Position.Point, VControl.Width, VControl.Height ) ) );
    end;
    Result := VRect.Width + Padding.Right;
  end;
end;

function TControlHelper.ChildrenHeight: Single;
var
  VIndex: Integer;
  VControl: TControl;
  VRect: TRectF;
begin
  VRect := TRectF.Empty;
  if not ( ClipChildren or SmallSizeControl ) and ( Controls <> nil ) then
  begin
    for VIndex := GetFirstVisibleObjectIndex to GetLastVisibleObjectIndex - 1 do
    begin
      VControl := Controls[ VIndex ];
      if VControl.Visible then
        VRect := UnionRect( VRect, VControl.Margins.MarginRect( TRectF.Create( VControl.Position.Point, VControl.Width, VControl.Height ) ) );
    end;
    Result := VRect.Height + Padding.Bottom;
  end;
end;
user3703876
  • 174
  • 12
1

I just submitted the following as a bug report. In the meantime I would suggest you calulate the bounds yourself, maybe even starting with the code below:

The documentation for FMX TControl.ChildrenRect states:

"Specifies the rectangle area occupied by the current control's children. ChildrenRect is a rectangle obtained by performing a union operation between the rectangles occupied by the control's children." - http://docwiki.embarcadero.com/Libraries/XE7/en/FMX.Controls.TControl.ChildrenRect

However, the code actually includes it's own bounds in the calculation:

function TControl.GetChildrenRect: TRectF;
var
  I: Integer;
  Control: TControl;
begin
  Result := AbsoluteRect;  <---*****This line
  { children }
  if not (ClipChildren or SmallSizeControl) and (FControls <> nil) then
    for I := GetFirstVisibleObjectIndex to GetLastVisibleObjectIndex - 1 do
    begin
      Control := FControls[I];
      if Control.Visible then
        Result := UnionRect(Result, Control.GetChildrenRect);
    end
end;

If this is intended behaviour then the documentation needs updating, otherwise it is a bug in the implementation.

Mike Sutton
  • 4,191
  • 4
  • 29
  • 42
  • Many thanks Mike for your help, I've been trying in the last 3 days for a tip and putting this code `Layout1.DeleteChildren; Layout1.Size.Height := 0;`it seems that `Layout1.ChildrenRect.Height` recalc the size, I think that it is not the best way but was a temporary solution. I think that your solution is the way to do it for now. – Juande Feb 16 '15 at 19:38
  • Why not take the code from the answer, remove the call to AbsoluteRect and initialise a rect at (0,0,0,0)? The rest of the routine should work fine, just take a TControl as a parameter instead of the implicit Self. – Mike Sutton Feb 17 '15 at 12:47