在以另一种形式的OnDestroy事件释放表单时访问冲突

时间:2018-04-24 14:53:29

标签: delphi delphi-7

我正在使用Delphi 7.我在释放表单时遇到访问冲突错误。

1)创建新的Application Delphi 7(Unit1)

2)添加新表格(单元2)

3)对于Unit1使用子句添加Unit2并写下代码

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, unit2, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  form2 : TForm2;
begin
  try
    form2 := TForm2.Create(Application);
    //form2.ShowModal;
  finally
    //FreeAndNil(form2);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Form2 <> nil then
    FreeAndNil(form2);
end;

end.

4)运行应用程序并关闭Form1 - 获取以下错误。

enter image description here

我不想在OnClose或OnCloseQuery上释放Form2对象,因为我在这些事件上有一些代码。我想在OnClose或OnCloseQuery之后释放Form2对象。

为什么我会收到错误以及如何解决此问题?

2 个答案:

答案 0 :(得分:4)

您描述的问题可以按照您的步骤在Delphi 7中重现。访问冲突的原因是Form2.dpr文件中自动处理(这使得应用程序成为表单的所有者),但您也尝试通过调用{{1}来控制其生命周期FreeAndNil(Form2) OnDestroy事件中的Form1事件。在您尝试释放表单时,它已被应用程序释放。

当应用程序(可能)即将终止(因为主要表单被销毁)时,为什么你试图释放Form2并不是很清楚。由于应用程序是所有者,您可以安全地让应用程序负责其职责。

您需要决定,您希望成为Form2的所有者。

  1. 如果您是,则应从自动处理表单列表中删除Form2(请参阅Project - Options - Forms并将Form2移至Available forms)。
  2. 如果您希望应用程序成为所有者,只需不Free表单,如果需要,可以使用hideshow方法来控制其可见性,但请将其保留应用程序根据其设计销毁它。
  3. 顺便说一下,TForm1.FormCreate()中的代码与您看到的AV无关。那个Form2是一个单独的实例,如果打算显示一个启动形式,那就没关系,如下所示:

    procedure TForm1.FormCreate(Sender: TObject);
    var
      form2 : TForm2;
    begin
      form2 := TForm2.Create(nil);
      try
        form2.ShowModal;
      finally
        form2.Free;
      end;
    end;
    

    表单不需要所有者,因此nil中的Create。由于变量form2是本地的,因此绝对没有必要将它变为零。

答案 1 :(得分:3)

问题是Form2将在unit2中声明,并再次在此表单的FormCreate中声明。你只是使用了错误的。

我建议从unit2中删除Form2的声明,只使用本单元中的声明,并将声明移到私有部分

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    Form2: TForm2; // Declare the form here, not in unit2
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form2 := TForm2.Create(nil);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // no need to check if Form2 exists, it is created in the FormCreate and will thus always exist
  // unless there is code somewhere that we cant see that destroys it.
  // Also no need to set the variable to nil as mentioned in the Tom's answer
  Form2.Free;
end;
相关问题