在运行时在 Firemonkey 中创建然后销毁 TLabel
Create and then destroy TLabels at runtime in Firemonkey
我正在尝试在运行时生成 TLabel 并使用此代码将它们插入到 VertScrollBox 中;
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;
标签显示没有任何问题,但是当我尝试使用此代码释放生成的标签时:
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;
然后我总是得到错误 'Argument out of range'。
如何在运行时正确删除添加到 VertScrollBox 的 TLabel?
您使用以下行开始循环
for i := 0 to ComponentCount-1 do
但是当您释放一个组件时,它会将自己从组件列表中删除,作为其清理代码的一部分。因此,每个被释放的组件都会将列表的大小减少 1。ComponentCount-1
表达式在 for 循环开始时被评估一次,因此不会更新以反映更改。
即使你能解决这个问题,你的循环也会跳过项目。也就是说,如果您删除了第 3 项,第 4 项现在将变为第 3 项,但您的循环将前进到第 4 项。
不过,解决这个问题的方法很简单。简单地向后迭代列表:
for i := ComponentCount-1 downto 0 do
值得一提的是,您的代码实际上只会释放 Windows 和 OSX 上的项目。在移动设备上,编译器使用 ARC,它只在对象的所有引用都被删除后才释放对象。 solution/work around/fudge[1] 是为组件调用 DisposeOf
而不是 Free
。
顺便说一句,as
运算符已经保证对象是 Assigned
,因此不需要额外的测试。不需要 FreeAndNil
一个局部变量,它将被重新分配或直接超出范围,并且在释放对象之前不需要强制转换它。由于 Free(或 DisposeOf
)方法存在于共同祖先 class 中,编译器将为任何后代 classes.
解析链接
因此,您的代码可以简化为:
var
i: integer;
begin
for i := ComponentCount-1 downto 0 do
begin
if Components[i] is TLabel then
if StartsText('Label', (Components[i] as TLabel).Name) then
Components[i].DisposeOf;
end;
end;
[1] - 取决于您与谁交谈。
我正在尝试在运行时生成 TLabel 并使用此代码将它们插入到 VertScrollBox 中;
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;
标签显示没有任何问题,但是当我尝试使用此代码释放生成的标签时:
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;
然后我总是得到错误 'Argument out of range'。
如何在运行时正确删除添加到 VertScrollBox 的 TLabel?
您使用以下行开始循环
for i := 0 to ComponentCount-1 do
但是当您释放一个组件时,它会将自己从组件列表中删除,作为其清理代码的一部分。因此,每个被释放的组件都会将列表的大小减少 1。ComponentCount-1
表达式在 for 循环开始时被评估一次,因此不会更新以反映更改。
即使你能解决这个问题,你的循环也会跳过项目。也就是说,如果您删除了第 3 项,第 4 项现在将变为第 3 项,但您的循环将前进到第 4 项。
不过,解决这个问题的方法很简单。简单地向后迭代列表:
for i := ComponentCount-1 downto 0 do
值得一提的是,您的代码实际上只会释放 Windows 和 OSX 上的项目。在移动设备上,编译器使用 ARC,它只在对象的所有引用都被删除后才释放对象。 solution/work around/fudge[1] 是为组件调用 DisposeOf
而不是 Free
。
顺便说一句,as
运算符已经保证对象是 Assigned
,因此不需要额外的测试。不需要 FreeAndNil
一个局部变量,它将被重新分配或直接超出范围,并且在释放对象之前不需要强制转换它。由于 Free(或 DisposeOf
)方法存在于共同祖先 class 中,编译器将为任何后代 classes.
因此,您的代码可以简化为:
var
i: integer;
begin
for i := ComponentCount-1 downto 0 do
begin
if Components[i] is TLabel then
if StartsText('Label', (Components[i] as TLabel).Name) then
Components[i].DisposeOf;
end;
end;
[1] - 取决于您与谁交谈。