自删除按钮

k0t*_*0tt 0 delphi free panel self button

我有一个 TScrollBox,里面有一堆 TPanel,还有一些在运行时生成的 TButton。我需要在单击一个 TButton 时删除 TPanel,但在 OnClick 中执行此操作会导致访问冲突......

procedure TMainForm.ButanClick(Sender: TObject);
var
  vParentPanel: TPanel;
begin
  if (string(TButton(Sender).Name).StartsWith('L')) then
  begin
    TButton(Sender).Caption := 'YARE YARE DAZE';
  end
  else
  begin
    vParentPanel := TPanel(TButton(Sender).GetParentComponent());
    TheScrollBox.RemoveComponent(vParentPanel);
    vParentPanel.Destroy();
    // access violation but the panel is removed
  end;
end;

procedure TMainForm.Button3Click(Sender: TObject);
var
  i: Integer;
  vPanel: TPanel;
  vButton: TButton;
begin
  for i := 0 to 20 do
  begin
    vPanel := TPanel.Create(TheScrollBox);
    vPanel.Align := alTop;
    vPanel.Parent := TheScrollBox;

    vButton := TButton.Create(vPanel);
    vButton.Align := alLeft;
    vButton.Parent := vPanel;
    vButton.Name := 'L_butan' + IntToStr(i);
    vButton.OnClick := ButanClick;

    vButton := TButton.Create(vPanel);
    vButton.Align := alRight;
    vButton.Parent := vPanel;
    vButton.Name := 'R_butan' + IntToStr(i);
    vButton.OnClick := ButanClick;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 5

您无法从的事件内部安全地销毁父级TPanel(或自身) 。事件处理程序退出后, VCL 仍然需要访问/一段时间。因此,您需要将销毁延迟到处理程序退出之后。最简单的方法是使用来调用,例如:TButtonTButtonOnClickTPanelTButtonTThread.ForceQueue()TObject.Free()TPanel

procedure TMainForm.ButanClick(Sender: TObject);
var
  vButton: TButton;
begin
  vButton := TButton(Sender);
  if vButton.Name.StartsWith('L') then
  begin
    vButton.Caption := 'YARE YARE DAZE';
  end
  else
  begin
    TThread.ForceQueue(nil, vButton.Parent.Free);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

意志在毁灭过程中将TPanel自己从其中移除。TScrollBox您不需要手动处理该步骤。