Reputation: 2645
I have a form with a TFlowLayout
inside the TVertScrollbox
.
I fill the TFlowLayout
with some frames at runtime, that can have variable height.
I´d like to set the VertScrollBox.ContentBounds
to be able to scroll from the first to the last frame added.
It seems I have to use CalcContentBounds
of the TVertScrollBox
. How could I do it?
procedure TForm1.Button2Click(Sender: TObject);
var
fr:TfrFrameItem;
i:integer;
begin
FlowLayout1.BeginUpdate;
for i:=FlowLayout1.ControlsCount-1 downto 0 do begin
FlowLayout1.Controls[i].Free;
end;
for i:=0 to 100 do begin
fr:=TfrFrameItem.Create(FlowLayout1);
fr.Name:='fr'+FlowLayout1.ControlsCount.ToString();
fr.Parent:=FlowLayout1;
fr.Visible:=True;
end;
FlowLayout1.EndUpdate;
VertScrollBox1.RealignContent;
end;
procedure TForm1.VertScrollBox1CalcContentBounds(Sender: TObject;
var ContentBounds: TRectF);
begin
ContentBounds.Bottom:=?????
end;
Unit1.pas
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
FMX.Controls.Presentation, FMX.StdCtrls,Math, FMX.Objects, FMX.Edit,
FMX.ListBox, FMX.ScrollBox, FMX.Memo, FMX.TabControl, FMX.MultiView;
type
TForm1 = class(TForm)
VertScrollBox1: TVertScrollBox;
FlowLayout1: TFlowLayout;
Panel1: TPanel;
ToolBar1: TToolBar;
Button2: TButton;
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses uFrameitem;
{$R *.fmx}
procedure TForm1.Button2Click(Sender: TObject);
var
lFrame:TfrFrameItem;
i:integer;
lHeight:single;
begin
FlowLayout1.BeginUpdate;
try
for i := FlowLayout1.ControlsCount - 1 downto 0 do
FlowLayout1.Controls[i].Free;
lHeight := 0;
for i := 0 to 100 do
begin
lFrame := TfrFrameItem.Create(FlowLayout1);
lFrame.Name := 'fr' + FlowLayout1.ControlsCount.ToString;
lFrame.Parent := FlowLayout1;
lFrame.Visible := True;
lHeight := Max(lHeight, lFrame.Position.Y + lFrame.Height);
end;
FlowLayout1.Height := lHeight;
finally
FlowLayout1.EndUpdate;
end;
VertScrollBox1.RealignContent;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var i:integer;
begin
for i:=FlowLayout1.ControlsCount-1 downto 0 do begin
FlowLayout1.Controls[i].Free;
end;
end;
end.
Unit1.fmx
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 647
ClientWidth = 1057
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnDestroy = FormDestroy
DesignerMasterStyle = 0
object VertScrollBox1: TVertScrollBox
Align = Client
Size.Width = 1057.000000000000000000
Size.Height = 568.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
Viewport.Width = 1057.000000000000000000
Viewport.Height = 568.000000000000000000
object FlowLayout1: TFlowLayout
Align = Top
Size.Width = 1057.000000000000000000
Size.Height = 177.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
Justify = Left
JustifyLastLine = Left
FlowDirection = LeftToRight
end
end
object Panel1: TPanel
Align = Bottom
Position.Y = 608.000000000000000000
Size.Width = 1057.000000000000000000
Size.Height = 39.000000000000000000
Size.PlatformDefault = False
TabOrder = 2
end
object ToolBar1: TToolBar
Size.Width = 1057.000000000000000000
Size.Height = 40.000000000000000000
Size.PlatformDefault = False
TabOrder = 3
object Button2: TButton
Align = Right
Position.X = 977.000000000000000000
Size.Width = 80.000000000000000000
Size.Height = 40.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
Text = 'Preencher'
OnClick = Button2Click
end
end
end
uFrameItem.pas
unit uFrameItem;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
FMX.Controls.Presentation, FMX.Objects, FMX.Layouts;
type
TfrFrameItem = class(TFrame)
Layout1: TLayout;
Rectangle1: TRectangle;
Label1: TLabel;
Label2: TLabel;
Label4: TLabel;
Layout2: TLayout;
Label3: TLabel;
Label6: TLabel;
Layout3: TLayout;
Label7: TLabel;
Label8: TLabel;
Button1: TButton;
Rectangle2: TRectangle;
Label5: TLabel;
procedure Layout2Resize(Sender: TObject);
procedure Label2Resize(Sender: TObject);
private
{ Private declarations }
function ListChildren(Obj : TFMXObject; Level : Integer):double;
public
{ Public declarations }
end;
implementation
{$R *.fmx}
function TfrFrameItem.ListChildren(Obj : TFMXObject; Level : Integer):double;
var i: Integer;
begin
for i := 0 to Obj.ChildrenCount-1 do begin
if Obj.Children[i].Tag=1 then begin
if (Obj.Children[i] is TLayout) then
result:=result+TLayout(Obj.Children[i]).Height;
if (Obj.Children[i] is TLabel) then
result:=result+TLabel(Obj.Children[i]).Height;
if (Obj.Children[i] is TImageControl) then
result:=result+TImageControl(Obj.Children[i]).Height;
if (Obj.Children[i] is TButton) then
result:=result+TButton(Obj.Children[i]).Height;
end;
result:=result+ListChildren(Obj.Children[i],Level+1);
end;
end;
procedure TfrFrameItem.Label2Resize(Sender: TObject);
const
ExtraHeigthOfLayout = 10;
var
Lbl: TLabel;
Layout: TLayout;
begin
Layout2Resize(Sender);
end;
procedure TfrFrameItem.Layout2Resize(Sender: TObject);
const
ExtraHeigthOfLayout = 10;
var
Lay: Tlayout;
Layout: TLayout;
i:integer;
hh:double;
begin
hh:=ListChildren(Layout1,0);
Layout1.Height:=hh+60;
end;
end.
uFrameItem.fmx
object frFrameItem: TfrFrameItem
Size.Width = 210.000000000000000000
Size.Height = 391.000000000000000000
Size.PlatformDefault = False
object Layout1: TLayout
StyleName = 'mystyle'
Position.X = 5.000000000000000000
Position.Y = 5.000000000000000000
Size.Width = 201.000000000000000000
Size.Height = 381.000000000000000000
Size.PlatformDefault = False
TabOrder = 2
object Rectangle1: TRectangle
Align = Client
Fill.Color = claLimegreen
Padding.Left = 5.000000000000000000
Padding.Right = 5.000000000000000000
Size.Width = 201.000000000000000000
Size.Height = 381.000000000000000000
Size.PlatformDefault = False
object Label1: TLabel
Tag = 1
Align = Top
StyledSettings = [Family, FontColor]
Padding.Top = 10.000000000000000000
Padding.Bottom = 10.000000000000000000
Margins.Top = 10.000000000000000000
Margins.Bottom = 10.000000000000000000
Position.X = 5.000000000000000000
Position.Y = 10.000000000000000000
Size.Width = 191.000000000000000000
Size.Height = 17.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Size = 18.000000000000000000
TextSettings.Font.Style = [fsBold]
TextSettings.HorzAlign = Center
Text = 'Raio x de quadril'
end
object Label2: TLabel
Tag = 1
Align = Top
AutoSize = True
StyledSettings = [Family, FontColor]
Padding.Top = 10.000000000000000000
Padding.Bottom = 10.000000000000000000
Margins.Top = 10.000000000000000000
Margins.Bottom = 10.000000000000000000
Position.X = 5.000000000000000000
Position.Y = 84.000000000000000000
Size.Width = 191.000000000000000000
Size.Height = 24.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Size = 18.000000000000000000
TextSettings.Font.Style = [fsBold]
Text = 'Raio x de quadril '
OnResize = Label2Resize
end
object Label4: TLabel
Tag = 1
Align = Top
StyledSettings = [Family, FontColor]
Padding.Top = 10.000000000000000000
Padding.Bottom = 10.000000000000000000
Margins.Top = 10.000000000000000000
Margins.Bottom = 10.000000000000000000
Position.X = 5.000000000000000000
Position.Y = 47.000000000000000000
Size.Width = 191.000000000000000000
Size.Height = 17.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Size = 18.000000000000000000
TextSettings.Font.Style = [fsBold]
TextSettings.HorzAlign = Center
Text = 'Raio x de quadril'
end
object Layout2: TLayout
Tag = 1
Align = Top
Position.X = 5.000000000000000000
Position.Y = 151.000000000000000000
Size.Width = 191.000000000000000000
Size.Height = 37.000000000000000000
Size.PlatformDefault = False
TabOrder = 3
OnResize = Layout2Resize
object Label3: TLabel
Align = FitLeft
StyledSettings = [Family, FontColor]
Margins.Top = 5.000000000000000000
Margins.Bottom = 5.000000000000000000
Position.Y = 5.000000000000000000
Size.Width = 42.678131103515620000
Size.Height = 27.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Size = 18.000000000000000000
TextSettings.Font.Style = [fsBold]
Text = 'De:'
end
object Label6: TLabel
Align = Client
StyledSettings = [Family, FontColor]
Size.Width = 148.321868896484400000
Size.Height = 37.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Size = 16.000000000000000000
TextSettings.Font.Style = [fsBold]
Text = 'R$ 10,00'
end
end
object Layout3: TLayout
Tag = 1
Align = Top
Position.X = 5.000000000000000000
Position.Y = 118.000000000000000000
Size.Width = 191.000000000000000000
Size.Height = 33.000000000000000000
Size.PlatformDefault = False
TabOrder = 4
object Label7: TLabel
Align = FitLeft
StyledSettings = [Family, FontColor]
Margins.Top = 5.000000000000000000
Margins.Bottom = 5.000000000000000000
Position.Y = 5.000000000000000000
Size.Width = 43.193511962890620000
Size.Height = 23.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Size = 18.000000000000000000
TextSettings.Font.Style = [fsBold]
Text = 'Por:'
end
object Label8: TLabel
Align = Client
StyledSettings = [Family, FontColor]
Size.Width = 147.806488037109400000
Size.Height = 33.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Size = 16.000000000000000000
TextSettings.Font.Style = [fsBold]
Text = 'R$ 10,00'
end
end
end
object Button1: TButton
StyledSettings = [Family, FontColor]
Position.X = 32.000000000000000000
Position.Y = 320.000000000000000000
Size.Width = 129.000000000000000000
Size.Height = 41.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
Text = 'Comprar'
TextSettings.Font.Size = 20.000000000000000000
TextSettings.Font.Style = [fsBold]
end
object Rectangle2: TRectangle
Opacity = 0.800000011920928900
Position.X = 156.000000000000000000
Position.Y = -7.000000000000000000
Size.Width = 50.000000000000000000
Size.Height = 25.000000000000000000
Size.PlatformDefault = False
Stroke.Color = claChocolate
object Label5: TLabel
Align = Client
StyledSettings = [Size, FontColor]
Size.Width = 50.000000000000000000
Size.Height = 25.000000000000000000
Size.PlatformDefault = False
TextSettings.Font.Family = 'Segoe UI Semibold'
TextSettings.Font.Style = [fsBold]
TextSettings.HorzAlign = Center
Text = '100%'
end
end
end
end
Upvotes: 1
Views: 3920
Reputation: 13
Although this is for TVertScrollBox, I think this issue may be related/similar to the issues I've had with TScrollBox. TScrollBox wasn't updating (immediately) its boundaries/targets when the size\position of control within it, changed. It did update eventually after a repaint etc. I had several hours of headbanging before I got this solution.
I don't like subclassing, but in this case, I had to do it to TScrollCalculations so as I could access the protected procedure DoChanged.
TMyScrollCalculations=class(TScrollCalculations)
public
procedure DoChanged;override;
end;
When I changed the size of a control within my TScrollBox called ScrollBox1, I then called
TMyScrollCalculations(ScrollBox1).DoChanged;
And this allowed me to set the properties (in my case ViewportPosition) of the ScrollBox with the control's new boundaries correctly updated.
Upvotes: 0
Reputation: 1555
You don't need to change the TVertScrollBox
at all. It automatically adjusts to its content. All you need is to change the size of the TFlowLayout
. In this case it is necessary to recalculate the size whenever the size of the form is changed.
So you must replace VertScrollBox1.RealignContent
with Self.Resize
and then assign form's OnResize
event.
procedure TForm1.FormResize(Sender: TObject);
begin
if FlowLayout1.ControlsCount > 0 then
FlowLayout1.Height := FlowLayout1.Controls.Last.BoundsRect.Bottom
else
FlowLayout1.Height := VertScrollBox1.Height;
end;
Upvotes: 1