Delphi 2007 MDI 窗体销毁序列问题

Delphi 2007 MDI Form Destroy Sequence Issue

我有一个奇怪的问题,我似乎无法弄清楚。我有一个 MDI 子窗体,上面有一个 TListView 组件。在此列表视图中,我添加了一些列表项,其中数据属性指向相关对象。在 OnFormDestroy 事件中,我执行类似于以下的操作来清理这些对象:

Procedure TMDIChildForm1.FormDestroy(Sender: TObject);
Begin
  For I := 0 To lvLabour.Items.Count - 1 Do
    TLabourItem(lvLabour.Items[I].Data).Free;
  lvLabour.Items.Clear;
End;

现在,如果我关闭表单本身但让应用程序保持打开状态,这会正常工作。它将通过释放关联对象的每个项目。但是,如果我只是完全关闭应用程序而不先关闭 MDI 窗体,当它到达上面的代码时,项目计数为 0。这意味着在调用 FormDestroy 方法之前项目已从列表中清除。

因为只有在应用程序关闭时才会发生这种情况,所以没有内存泄漏。我只是将应用程序设置为在调试时显示内存泄漏,当我收到内存泄漏消息并且无法弄清楚原因时,这让我很烦。

发生这种情况是因为无论出于何种原因,终止过程都会在您的代码到达 运行 之前清除列表视图。但是有更好的方法来处理这个问题。好吧,有几个更好的方法可以说实话。

从离你最近的地方开始,你应该使用列表视图的OnDeletion事件来执行项目整理。每当删除列表项时都会触发此事件。您的事件处理程序将具有以下原型:

procedure ListView1Deletion(Sender: TObject; Item: TListItem);

在此事件处理程序中,对 Item.Data 中保存的对象调用 Free。以这种方式完成后,无论列表及其项目如何被销毁,您都可以确保相关数据被销毁。

我推荐的另一种方法涉及更多工作。不要使用包含对数据的引用的列表项,而是使用虚拟列表视图。在这种操作模式下,每当列表视图控件需要绘制项目,或查询它们的属性和状态时,它就会调用控件的事件来按需获取信息。这避免了您需要将数据对象的生命周期与显示它的 GUI 的生命周期相结合。