At design time, I create a TScrollBox which will be the parent of TLayouts created at runtime. The Layouts will also contain Tlabels and Tedits like this:
var
Layout1: TLayout;
Label1: TLabel;
Edit1: TEdit;
begin
Layout1 := TLayout.Create(self);
Layout1.Parent := ScrollBox1;
Label1 := TLabel.Create(self);
Label1.Parent := Layout1;
Label1.Text := 'abc';
end;
Now I want to delete everything out like this procedure has never been called.
I have tried the following, but the program would just crash.
var
i : integer;
Item : TControl;
begin
for i := 0 to Scrollbox1.ControlCount - 1 do
begin
Item := Scrollbox1.controls[i];
Item.Free;
end;
end;
Can anyone please give me a hint?
When you remove a control, the index of the ones behind it in the control list
shifts down. I.e, you end up trying to access positions that do not exist.
You need to iterate the list downwards:
var
i : integer;
Item : TControl;
begin
for i := (Scrollbox1.ControlCount - 1) downto 0 do
begin
Item := Scrollbox1.controls[i];
Item.Free;
end;
end;
Another way is to stay always at index 0, free its control and check that you still have controls to free:
var
i : integer;
Item : TControl;
begin
while Scrollbox1.ControlCount > 0 do
begin
Item := Scrollbox1.controls[0];
Item.Free;
end;
end;
UPDATE
As @DavidHeffernan pointed out, there is nested parentage here. This means you should free your components from bottom up. One way to do it is by recursion.
Basically you would need a procedure to encapsulate the freeing of child controls. The code would be similar to following (please note this is just a small test I did and extra code may be required):
procedure freeChildControls(myControl : TControl; freeThisControl: boolean);
var
i : integer;
Item : TControl;
begin
if Assigned(myControl) then
begin
for i := (myControl.ControlsCount - 1) downto 0 do
begin
Item := myControl.controls[i];
if assigned(item) then
freeChildControls(item, childShouldBeRemoved(item));
end;
if freeThisControl then
FreeAndNil(myControl);
end;
end;
function childShouldBeRemoved(child: TControl): boolean;
begin
//consider whatever conditions you need
//in my test I just checked for the child's name to be layout1 or label1
Result := ...;
end;
In order to free the scrollbox1
child controls (but not itself) you would call it like this:
freeChildControls(scrollbox1, false);
Please note that I had to add the childShouldBeRemoved
function in order to avoid this recursive function to free child controls of the label
and layout
that you should leave for their destructors to free.
One possible solution to implement this function would be to use an object list
where you would add your created components, and then inside the function check if the passed child component has to be freed.
If you create components at runtime - use parent control as parameter of the constructor. Like Label1 := TLabel.Create(Layout1);
- so that the parent is also the owner. When you destroy Layout1
the Label1
also will be destroyed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With