Delphi 2007 MDI表单销毁序列问题

Delphi 2007 MDI表单销毁序列问题,delphi,memory-leaks,Delphi,Memory Leaks,我有一个奇怪的问题,我似乎无法解决。我有一个MDI子窗体,上面有一个TListView组件。在这个列表视图中,我添加了几个数据属性指向相关对象的列表项。在OnFormDestroy事件中,我执行类似于以下的操作来清理这些对象: Procedure TMDIChildForm1.FormDestroy(Sender: TObject); Begin For I := 0 To lvLabour.Items.Count - 1 Do TLabourItem(lvLabour.Items[

我有一个奇怪的问题,我似乎无法解决。我有一个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方法之前,这些项已从列表中清除


因为这只在应用程序关闭时发生,所以没有内存泄漏。我只是将应用程序设置为在调试时显示内存泄漏,当我收到内存泄漏消息时,它会让我感到恼火,并且无法找出原因。

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

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

procedure ListView1Deletion(Sender: TObject; Item: TListItem);
在该事件处理程序中,调用
Item.Data
中保存的对象的
Free
。通过这种方式,无论列表及其项如何销毁,都可以确保相关数据已销毁


我建议的另一种方法涉及更多的工作。使用虚拟列表视图代替包含数据引用的列表项。在这种操作模式下,每当列表视图控件需要绘制项或查询其属性和状态时,它都会调用控件的事件以按需获取信息。这避免了您需要将数据对象的生存期与显示它的GUI的生存期耦合起来。

这取决于ListView项与它们所引用的数据的关系,以及数据是显示给用户还是仅供私人使用,在这种情况下,在虚拟模式下使用ListView可能有些过分。一个较小的改变是将实际的数据项存储在一个单独的TList中,然后继续使用TListItem.data引用它们以方便使用。但是,当需要释放它们时,可以通过TList而不是TListView进行循环。虽然我通常同意在数据项存储在列表视图本身时使用
ondelection
,但我也建议注意这一点,因为有些版本的
ondelection
已被破坏,或者根本没有触发,或者在错误的时间或顺序触发。@David:谢谢。。。我甚至没有意识到TListViews有一个OnDelete事件,我已经和Delphi合作了15年了!事实上,我仍然很好奇,为什么在处理这个具体的例子时,列表项会被清除,但是哦,好吧。我相信我们可以解决这个问题,但我找不到这样做的动机@雷米利博:我会测试一下OnDeletion事件,因为它似乎是最快的改变。虽然我同意建立一个单独的TList可能更稳定,但考虑到我们的应用程序在任何地方都做这些事情,这也需要做很多工作。但是谢谢你的提示!