Search code examples
delphitextexpander

delphi set the TExpander height


i've a TExpander component and i add some TTexts to it at runtime , the issue i'm facing is : how can this Expander's height be set based on the Number of the TTexts , something like AutoSize ?

the code i'm using :

procedure TForm1.Button5Click(Sender: TObject);
var
  _DailyEvent:TDailyEvents;
  Eventstext:TText;
  _Y:Integer;
begin
    _Y:=10;
    For _DailyEvent in DailyEventsList do
    begin
             Eventstext:=TText.Create(Self);
             Eventstext.Position.Y := _Y;
             Eventstext.Align:=TAlignLayout.Top;
             Eventstext.Height:=25;
             Eventstext.TagString:=_DailyEvent.EventID;
             Eventstext.Text:=_DailyEvent.EventName;
             Eventstext.Parent:=Expander1;
             inc(_Y, 15);
    end;
    Expander1.Height:=?   

end;

here's what i get

Image demonstrating problem

thank you .


Solution

  • Actually, when you set Eventstext.Parent to expander1, this object added to protected field FContent. So, if you want calculate real size as sum of all inner controls, you must get this field.

    You can "override" TExpander class like this:

    type
      // declare new TExpander class before form declaration
      // thanks to this declaration we have access to protected fields
      TExpander = class(FMX.StdCtrls.TExpander)
      protected
        procedure DoExpandedChanged; override;
      public
        function GetRealRect: TRectF;
      end;
    
      TForm2 = class(TForm)
        expndr1: TExpander; // this is our new class, not "standart" TExpander
        btnAdd10: TButton;
        btnDelLast: TButton;
        procedure btnAdd10Click(Sender: TObject);
        procedure btnDelLastClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form2: TForm2;
    
    implementation
    
    {$R *.fmx}
    
    procedure TForm2.btnAdd10Click(Sender: TObject);
    var
      Eventstext: TText;
      i: integer;
      _Y: integer;
    begin
      _Y := 10;
      For i := 1 to 10 do
      begin
        Eventstext := TText.Create(Self);
        Eventstext.Position.Y := _Y;
        Eventstext.Align := TAlignLayout.Top;
        Eventstext.Height := 25;
        Eventstext.Text := i.ToString;
        Eventstext.Parent := expndr1;
        inc(_Y, 25);
      end;
      // of course, this is not real Autosize,
      // you can override AddObject in TExpander and change size in it,
      // but you can`t get access to RemoveObject in FContent...
      // thus, "AutoSize" will be limited only to adding items.
      // I think the current way is much better than override AddObject...
      expndr1.SetBoundsRect(expndr1.GetRealRect); 
      // or expndr1.height:=expndr1.GetRealRect.Height;
    end;
    
    procedure TForm2.btnDelLastClick(Sender: TObject);
    begin
      if expndr1.FContent.ChildrenCount <> 0 then
      begin
        expndr1.FContent.Children[expndr1.FContent.ChildrenCount - 1].Release;
        expndr1.SetBoundsRect(expndr1.GetRealRect);
      end;
    end;
    
    { TExpander }
    
    procedure TExpander.DoExpandedChanged;
    begin
      inherited;
      SetBoundsRect(GetRealRect);
    end;
    
    function TExpander.GetRealRect: TRectF;
    var
      i: integer;
      LControl: TControl;
    begin
      // above FContent are Button, Text and Checkbox
      Result.TopLeft := AbsoluteRect.TopLeft;
      Result.BottomRight := FContent.AbsoluteRect.TopLeft;
    
      if FIsExpanded then
        for i := 0 to FContent.ChildrenCount - 1 do
          if FContent.Children[i] is TControl then
          begin
            LControl := TControl(FContent.Children[i]);
            if LControl.Visible then
              UnionRectF(Result, Result, LControl.ChildrenRect);
          end;
      if Result.Width = 0 then // if there are no controls in FContent.
        Result.Width := Width;
    end;