这里已经讨论过了,但没有详细说明。
我在尝试关闭非模态子窗体时遇到了麻烦。我让它通知父母,但我得到了抽象错误和其他异常。我究竟做错了什么?父母是否必须释放非模态形式,或者再也不尝试通过该变量访问它?
主要形式:
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;
答案 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很好地清理。