I'm trying to generate TLabels at runtime and insert them into a VertScrollBox with this code;
var
i, f: integer;
RT_Label: TLabel;
begin
f:= 10;
for i := 0 to 20 do
begin
RT_Label := TLabel.Create(Self);
RT_Label.Name := 'Label' + i.ToString;
RT_Label.Text := 'SampleLabel' + i.ToString;
RT_Label.Position.Y := f;
RT_Label.Align := TAlignLayout.Top;
RT_Label.Parent := VertScrollBox1;
inc(f, 15);
end;
end;
Labels are displayed without any problem, but when I try to free the generated labels with this code:
var
i: integer;
LComponent: TComponent;
begin
for i := 0 to ComponentCount-1 do
begin
if( Components[i] is TLabel )then
if StartsText('Label', (Components[i] as TLabel).Name) then
begin
LComponent := (Components[i] as TLabel);
If Assigned(LComponent) then FreeAndNil(LComponent);
end;
end;
end;
Then I always get the error 'Argument out of range'.
How do I properly remove TLabels added to the VertScrollBox in runtime?
You start your loop with the following line
but when you free a component it removes itself from the Components list as part of it's clean-up code. So each component that gets freed reduces the size of the list by 1. The
ComponentCount-1
expression is evaluated once when the for loop start and thus does not get updated to reflect the change.Even if you could fix this your loop would be skipping items. I.e if your deleted item 3, item 4 would now become item 3, but your loop would advance to item 4.
The way around this is simple, though. Simply iterate the list backwards:
It's worth mentioning that your code will only actually free items on Windows and OSX. On mobile the compiler uses ARC which only frees an object once all references it have been removed. The solution/work around/fudge[1] is to call
DisposeOf
instead ofFree
for components.As an aside, the
as
operator already guarantees that the object isAssigned
, so no need for the extra test. There's no need toFreeAndNil
a local variable which will be either reassigned to or go straight out of scope, and there's no need to cast an object before freeing it. Since the Free (orDisposeOf
) method is present in the common ancestor class the compiler will resolve links for any descendant classes.Thus, your code can be simplified to:
[1] - depending on who you talk to.