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

Rob*_*ank 2 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;
Run Code Online (Sandbox Code Playgroud)

在NonModal.pas

procedure NonModalTForm.FormClose;
begin
  Callback; // calls parent
end;
Run Code Online (Sandbox Code Playgroud)

ska*_*adt 11

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

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

例如:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;
Run Code Online (Sandbox Code Playgroud)


Too*_*the 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;
Run Code Online (Sandbox Code Playgroud)

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


Nin*_*rry 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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • +1.当`Self`传递给`TfrmChild.Create()`而不是`Application`时,甚至不需要调用`FreeNotification()` - VCL中的所有权管理负责通知调用. (4认同)