You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi窗体动态添加控件遇ACCESS_VIOLATION错误求助

问题分析与解决方案

错误原因

你声明的FormBtns数组是TButton类型的指针数组,但数组中的每个元素默认都是nil(未初始化),没有实际创建TButton实例。直接访问FormBtns[1].OnClick或其他属性时,相当于访问空指针指向的内存,因此触发ACCESS_VIOLATION错误。

修复代码(基础版)

先为数组中的TButton创建实例,指定窗体为所有者(确保窗体销毁时自动释放按钮),再设置属性和事件:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    btnPos1: TButton;
    procedure btnNewClick(Sender: TObject);
    procedure Form1Close(Sender: TObject; var Action: TCloseAction);
    procedure Form1Create(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);
  private
    { Private declarations }
    procedure ReleaseFormBtns; // 释放动态创建的按钮
  public
    procedure LoadButtons;
    procedure ShowEditButtons; // 显示编辑相关按钮
  end;

var
    Form1: TForm1;
    FormBtns: array[1..6] of TButton; // 对应最多6个预定义位置

implementation

{$R *.dfm}

procedure TForm1.ReleaseFormBtns;
var
  i: Integer;
begin
  for i := Low(FormBtns) to High(FormBtns) do
  begin
    if Assigned(FormBtns[i]) then
    begin
      FormBtns[i].Free;
      FormBtns[i] := nil;
    end;
  end;
end;

procedure TForm1.LoadButtons;
begin
  ReleaseFormBtns; // 先释放旧按钮

  // 创建New按钮实例
  FormBtns[1] := TButton.Create(Self);
  FormBtns[1].Caption := '&New';
  FormBtns[1].OnClick := btnNewClick;
  FormBtns[1].Parent := Self; // 设置父控件为窗体
  FormBtns[1].Left := 340;
  FormBtns[1].Top := 20;

  // 隐藏预定义位置按钮,直接显示动态创建的按钮
  btnPos1.Visible := False;
  FormBtns[1].Visible := True;
end;

procedure TForm1.btnNewClick(Sender: TObject);
begin
  ShowEditButtons; // 点击New后显示Save、Clear、Cancel
end;

procedure TForm1.ShowEditButtons;
begin
  ReleaseFormBtns;

  // 创建Save按钮
  FormBtns[1] := TButton.Create(Self);
  FormBtns[1].Caption := '&Save';
  FormBtns[1].OnClick := btnSaveClick;
  FormBtns[1].Parent := Self;
  FormBtns[1].Left := 340;
  FormBtns[1].Top := 20;

  // 创建Clear按钮
  FormBtns[2] := TButton.Create(Self);
  FormBtns[2].Caption := '&Clear';
  FormBtns[2].OnClick := btnClearClick;
  FormBtns[2].Parent := Self;
  FormBtns[2].Left := 410;
  FormBtns[2].Top := 20;

  // 创建Cancel按钮
  FormBtns[3] := TButton.Create(Self);
  FormBtns[3].Caption := '&Cancel';
  FormBtns[3].OnClick := btnCancelClick;
  FormBtns[3].Parent := Self;
  FormBtns[3].Left := 480;
  FormBtns[3].Top := 20;

  // 隐藏预定义位置按钮
  btnPos1.Visible := False;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  // 保存逻辑
  ShowMessage('Save clicked');
  LoadButtons; // 保存后回到初始状态
end;

procedure TForm1.btnClearClick(Sender: TObject);
begin
  // 清空逻辑
  ShowMessage('Clear clicked');
end;

procedure TForm1.btnCancelClick(Sender: TObject);
begin
  // 取消逻辑,回到初始按钮状态
  LoadButtons;
end;

procedure TForm1.Form1Close(Sender: TObject; var Action: TCloseAction);
begin
  ReleaseFormBtns; // 确保释放所有动态按钮
  Application.Terminate;
end;

procedure TForm1.Form1Create(Sender: TObject);
begin
  LoadButtons;
end;

end.

更优实现建议

如果你的预定义位置是设计时在窗体上放置的空按钮(如btnPos1到btnPos6),可以直接复用这些按钮,无需动态创建新的TButton实例,这样更简洁且避免内存管理问题:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    btnPos1: TButton;
    btnPos2: TButton;
    btnPos3: TButton;
    btnPos4: TButton;
    btnPos5: TButton;
    btnPos6: TButton;
    procedure btnNewClick(Sender: TObject);
    procedure Form1Close(Sender: TObject; var Action: TCloseAction);
    procedure Form1Create(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);
  private
    { Private declarations }
    procedure ResetAllButtons; // 重置所有预定义位置按钮为隐藏状态
  public
    procedure ShowInitialButtons;
    procedure ShowEditButtons;
  end;

var
    Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ResetAllButtons;
begin
  btnPos1.Visible := False;
  btnPos2.Visible := False;
  btnPos3.Visible := False;
  btnPos4.Visible := False;
  btnPos5.Visible := False;
  btnPos6.Visible := False;
end;

procedure TForm1.ShowInitialButtons;
begin
  ResetAllButtons;
  btnPos1.Caption := '&New';
  btnPos1.OnClick := btnNewClick;
  btnPos1.Visible := True;
end;

procedure TForm1.btnNewClick(Sender: TObject);
begin
  ShowEditButtons;
end;

procedure TForm1.ShowEditButtons;
begin
  ResetAllButtons;

  btnPos1.Caption := '&Save';
  btnPos1.OnClick := btnSaveClick;
  btnPos1.Visible := True;

  btnPos2.Caption := '&Clear';
  btnPos2.OnClick := btnClearClick;
  btnPos2.Visible := True;

  btnPos3.Caption := '&Cancel';
  btnPos3.OnClick := btnCancelClick;
  btnPos3.Visible := True;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  ShowMessage('Save clicked');
  ShowInitialButtons; // 保存后回到初始状态
end;

procedure TForm1.btnClearClick(Sender: TObject);
begin
  ShowMessage('Clear clicked');
end;

procedure TForm1.btnCancelClick(Sender: TObject);
begin
  ShowInitialButtons;
end;

procedure TForm1.Form1Close(Sender: TObject; var Action: TCloseAction);
begin
  Application.Terminate;
end;

procedure TForm1.Form1Create(Sender: TObject);
begin
  ShowInitialButtons;
end;

end.

这种方式直接复用设计时的按钮控件,不需要手动管理动态控件的创建和释放,代码更简洁,也更符合VCL的使用习惯。

内容的提问来源于stack exchange,提问作者Skypilot65

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 02:52:16