如何关闭Delphi中的非模态窗体

问题描述:

这里已经讨论过了,但不是详细说明。如何关闭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

你的代码是切断你正在坐的分支的编程等价物。 – 2010-01-16 00:48:08

使用隐藏,如果你想显示窗口以后。

如果要关闭它,请使用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; 

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

你正在做你不应该做的事情。
在NonModalForm的onClose事件中,您调用一些直接释放它的代码,但它仍然在事件处理程序执行中,因此最终会产生一个无效的自身对象。
这就是为什么在表单上使用Release而不是Free的情况。

正如Gamecat指出的那样,只需简单地调用Close即可......
VCL的美妙之处在于它非常简单。

+0

>>作为Gamecat指出了这一点,只是简单地调用Close ...... RobertFrank 2010-01-16 00:28:45

+2

你的'回调函数与这个讨论无关,汤姆。正如你注意到的,你在表单的OnClose事件处理函数中调用它。这意味着在回调函数被调用时,*您的表单已经**了**关闭*,所以您的整个问题都没有意义:您不需要学习如何关闭表单,因为您已经完成即使你不知道你是如何管理它的。 – 2010-01-16 00:52:26

+0

没有回调过程,我如何避免父指向非模态表单的内存泄漏和/或悬挂指针?我必须释放NonModal指向的内存并将NonModal设置为零,所以我知道它没有被使用。 我可以看到的唯一解决办法是又逻辑的另一层:非模态形式,在关闭时,调用回调到母体,它设置一个标志“非模态形式封闭”为True。后来(当本身关闭或想重新使用非模态形式,它会检查这个标志,并释放内存。 对不起,这个挥之不去,但我真的试图找出了这一点,而不 – RobertFrank 2010-01-17 00:41:48

您可以致电close从FormClose事件以外的其他地方关闭窗体。在FormClose情况下,只需设置等于行动,以执行下列操作之一:

  • caFree - 处置形式的完全
  • caMinimize - 最小化形式
  • caHide - 隐藏形式
  • caNone - 忽略收盘

例如:

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

当其他组件被释放时,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方法来注册自己,当子窗体被破坏收到通知。

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

在孩子TfrmChild本身,你不必做任何事情,但什么skamradt写道:就在参数Actionb设置为caFree在OnClose事件。

+4

+1。当'Self'传递给'TfrmChild.Create()'而不是'Application'时,甚至不需要调用'FreeNotification()' - VCL中的所有权管理负责通知调用。 – mghie 2010-01-18 04:58:28

+0

这里唯一的工作决定。只有它将封闭格式设置为“nil”。工作很好。我不知道为什么有更少的选票 – 2017-06-10 08:46:50

不使用callback

只需拨打FreeAndNil(Self);以释放是为表单创建的所有内存资源。

记住这是你的实现代码创建的*对象。由Delphi设计的表单设计器创建的对象非常好。

+0

我不认为这个答案补充了已经给出的其他人。其次,作为[这个答案](http://*.com/a/2075484/757830)(特别是[这个评论])(http://*.com/questions/2075405/how-to-close -non-modal-form-in-delphi#comment2006057_2075484))声明,释放其事件处理程序中的表单实际上是不行的。对不起,-1。 – NGLN 2013-12-11 21:40:13