如何关闭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;
使用隐藏,如果你想显示窗口以后。
如果要关闭它,请使用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的美妙之处在于它非常简单。
>>作为Gamecat指出了这一点,只是简单地调用Close ...... RobertFrank 2010-01-16 00:28:45
你的'回调函数与这个讨论无关,汤姆。正如你注意到的,你在表单的OnClose事件处理函数中调用它。这意味着在回调函数被调用时,*您的表单已经**了**关闭*,所以您的整个问题都没有意义:您不需要学习如何关闭表单,因为您已经完成即使你不知道你是如何管理它的。 – 2010-01-16 00:52:26
没有回调过程,我如何避免父指向非模态表单的内存泄漏和/或悬挂指针?我必须释放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事件。
+1。当'Self'传递给'TfrmChild.Create()'而不是'Application'时,甚至不需要调用'FreeNotification()' - VCL中的所有权管理负责通知调用。 – mghie 2010-01-18 04:58:28
这里唯一的工作决定。只有它将封闭格式设置为“nil”。工作很好。我不知道为什么有更少的选票 – 2017-06-10 08:46:50
不使用callback
只需拨打FreeAndNil(Self);
以释放是为表单创建的所有内存资源。
记住这是你的实现代码创建的*对象。由Delphi设计的表单设计器创建的对象非常好。
我不认为这个答案补充了已经给出的其他人。其次,作为[这个答案](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
你的代码是切断你正在坐的分支的编程等价物。 – 2010-01-16 00:48:08