Delphi-从TPanel中删除运行时生成的按钮

Delphi-从TPanel中删除运行时生成的按钮,delphi,Delphi,我有几个Tpanel在运行时填充了按钮。但是,下面我用来将按钮从父面板中释放的代码有时会生成访问冲突错误 procedure TfrmTakeOrder.FreeItemButtons(buttons : array of TButton); var cnt,i : integer; begin for i := 0 to gridLayoutItems.ControlCount - 1 do begin buttons[i].Free; buttons

我有几个Tpanel在运行时填充了按钮。但是,下面我用来将按钮从父面板中释放的代码有时会生成访问冲突错误

procedure TfrmTakeOrder.FreeItemButtons(buttons : array of TButton);
var
  cnt,i : integer;
begin

  for i := 0 to gridLayoutItems.ControlCount - 1 do
    begin
      buttons[i].Free;
      buttons[i] := nil;
    end;

end;

有更好的方法吗?请记住,其他面板也有按钮,我希望“本地化”释放与其他面板不相关的按钮。

也许最好使用
长度(按钮)-1
而不是
gridLayoutItems.ControlCount-1
,后者可能不同。

是。使用
for i:=低(按钮)到高(按钮)do

您必须像其他答案状态一样更正for循环的边界。还有一件事:

如何创建按钮?如果您创建具有所有者的按钮,即

buttons [i] := TButton.Create (Panel);
然后,您不能手动释放它们。店主会负责的。在这种情况下,只需使用

buttons [i] := TButton.Create (nil);

在我看来,您试图删除TPanel中的所有按钮,而该面板仅包含按钮

试试这个:

while gridLayoutItems.ControlCount > 0 do
  gridLayoutItems.Controls[0].Free;
如果:

  • 该面板只有按钮,并且
  • 您的阵列在多个面板上具有所有按钮
然后使用:

var
  I: Integer;
  Button: TControl;
begin
  for I := GridLayoutItems.ControlCount - 1 downto 0 do
  begin
    Button := GridLayoutItems.Controls[I];
    Button.Free;
    { Find the index of Button in the Buttons array };
    { Erase that item from the array };
  end;
end;
但在这种情况下,按钮的TList比数组方便得多,因为这样代码就变成:

var
  I: Integer;
  Button: TControl;
begin
  for I := GridLayoutItems.ControlCount - 1 downto 0 do
  begin
    Button := GridLayoutItems.Controls[I];
    Button.Free;
    Buttons.Remove(Button);
  end;
end;

在Delphi的最新版本(如XE5)中,Free不再存在。我使用销毁而不是释放解决了此问题。

如果您只想从父面板释放按钮:

var i : integer
begin
i := 0;
while Panel1.ControlCount > i do
  if Panel1.Controls[i] is TButton then
     Panel1.Controls[i].Free
  else inc(i);
end;

您可以使用此代码

for i := 0 to ComponentCount-1 do
 begin
  if ( Components[ i ] is TPanel ) then
  (Components[ i ] as TPanel ).free;
 end;

可能
,因为即使
gridLayoutItems
恰好只包含这些按钮,释放这些按钮会使
ControlCount
减少:您会中途停止!不要费心设置
按钮[i]:=nil
,因为
按钮
是函数的一个参数,当函数返回时,新值会丢失。我不知道动态数组是通过复制而不是引用传递的。说得好。你不会中途停下来的,@Cosmin。for循环边界在循环开始时计算一次;它们不会在循环运行时重新计算。@Ba_ufiend,动态数组是通过引用传递的。但这不是一个动态数组。这是一个开放数组。我在表单上有几个Tpanel。这不也可以得到其他面板中的按钮数吗?如果将按钮存储在一个数组中,它当然会从所有面板中删除按钮。执行
按钮[I]:=TButton.Create(无论什么)
然后释放按钮完全可以。当按钮被释放时,它的所有者会收到一个通知,将其从其拥有的对象列表中删除,这样它就不会再次释放它。也就是说,如果按钮被释放是因为窗体在运行时需要更改:如果释放按钮的代码是从窗体的析构函数调用的,那么这是毫无意义的,并且有潜在的危险。@Cosmin:谢谢提醒,我不知道。始终认为它是
所有者
或手动
免费
。但请确保放弃自己的按钮阵列。否则,您将引用阵列中已释放的内存,如果您尝试使用它们,将遇到访问冲突。