如何在Delphi中关闭非模态表单

时间:2010-01-15 23:20:35

标签: delphi

这里已经讨论过了,但没有详细说明。

我在尝试关闭非模态子窗体时遇到了麻烦。我让它通知父母,但我得到了抽象错误和其他异常。我究竟做错了什么?父母是否必须释放非模态形式,或者再也不尝试通过该变量访问它?

主要形式:

NonModal := NonModalTForm.Create(Self);
NonModal.Callback := Callback;
NonModal.Show;

Procedure TForm.Callback; // called by non-modal form when closing 
begin
   FreeAndNil(NonModal);  // or should this just be NonModal := nil so I don't try to access a dangling pointer?
end;

在NonModal.pas中

procedure NonModalTForm.FormClose;
begin
  Callback; // calls parent
end;

5 个答案:

答案 0 :(得分:11)

您调用close以从FormClose事件以外的其他位置关闭您的表单。在FormClose事件中,只需将Action设置为等于以下之一:

  • caFree - 完全处理表格
  • caMinimize - 最小化表单
  • caHide - 隐藏表单
  • caNone - 忽略关闭

例如:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

答案 1 :(得分:6)

如果您想稍后显示该窗口,请使用隐藏。

如果要关闭它,请使用关闭。 (关闭主窗口,关闭应用程序)。 Close的确切操作取决于表单参数。

请参阅关闭来源:

procedure TCustomForm.Close;
var
  CloseAction: TCloseAction;
begin
  if fsModal in FFormState then
    ModalResult := mrCancel
  else
    if CloseQuery then begin
      if FormStyle = fsMDIChild then
        if biMinimize in BorderIcons then
          CloseAction := caMinimize 
        else
          CloseAction := caNone
      else
        CloseAction := caHide;
      DoClose(CloseAction);
      if CloseAction <> caNone then
        if Application.MainForm = Self then 
          Application.Terminate
        else if CloseAction = caHide then 
          Hide
        else if CloseAction = caMinimize then 
          WindowState := wsMinimized
        else 
          Release;
    end;
end;

但要小心免费。 Windows窗口队列中可能会有一些消息可能导致崩溃。更好地使用Release来清理窗口。因为这会在释放之前等待消息。

答案 2 :(得分:6)

VCL已经有一种机制,可以在释放其他组件时通知组件。你可以这样使用它;

type
  TfrmParent = class(TForm)
    btnShowChild: TButton;
    procedure btnShowChildClick(Sender: TObject);
  private
    FChild: TfrmChild;
  public
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  end;


procedure TfrmParent.btnShowChildClick(Sender: TObject);
begin
  // Check status of child
  if FChild = nil then
  begin
    // Child does not exist, create it
    FChild:= TfrmChild.Create(Application);
    FChild.Show;

    // Ask Child to notify us when it is destroyed
    FChild.FreeNotification(Self);
  end
  else
  begin
    // Child already exists
    FChild.Show;
  end;
end;

procedure TfrmParent.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;

  if (AComponent = FChild) and (Operation = opRemove) then
  begin
    // FChild is about to be freed, so set reference to Child to nil
    FChild:= nil;
  end;
end;

创建子表单后,使用创建的表单的FreeNotification方法注册自己,以便在子表单被销毁时收到通知。

要对通知作出反应,请覆盖通知方法。在那里,您可以找出销毁的组件,并将其与记住的子表单引用进行比较。收到通知后,只需将子表单的引用设置为nil。

在子TfrmChild本身你不需要做任何其他事情,除了skamradt编写的内容:只需在OnClose事件中将参数Actionb设置为caFree。

答案 3 :(得分:4)

你正在做你不该做的事 在关闭NonModalForm的onClose时,你调用一些直接释放它的代码,而它仍然在事件处理程序执行中,所以你最终得到一个无效的自我对象。
这就是为什么在表单上使用Release而不是Free的典型案例。

正如Gamecat指出的那样,只需简单地调用Close ...
VCL的美妙之处往往就是那么简单。

答案 4 :(得分:-2)

请勿使用callback

只需调用FreeAndNil(Self);即可释放为表单创建的所有内存资源。

请记住释放由实现代码创建的对象。表单设计器创建的对象由Delphi很好地清理。