Delphi - 如何在一个窗体的ComponentCount减少时中断程序

4

以下代码是从Toolbar2000复制的。它是从一个INI文件中读取工具栏位置和停靠状态的例程的一部分。我在初始化期间调用这个例程。以下代码正在迭代主窗体(OwnerComponent)上的所有组件,并加载它找到的任何工具栏的设置。

for I := 0 to OwnerComponent.ComponentCount-1 do begin
  ToolWindow := OwnerComponent.Components[I];  //  <------------------------
....

这个迭代需要一些时间(几秒钟-表单上有1500多个组件),并且我在所示点处遇到了一个范围错误。 我已经确定,当这个循环正在执行时,主表单的一个或多个项目正在被删除,因此一旦发生这种情况,循环尝试访问数组末尾之后的一个位置(可能最好将其编码为“downto”for循环来防止这种情况)。

无论如何,我需要找出主窗体失去组件的位置。 有人可以给我任何关于如何在Delphi 2006中进行调试的提示吗? 我不希望在程序的这个点释放任何主要表单组件。

更新

我发现当我在设计时重新定位工具栏的默认停靠位置时,我不小心将其停靠在另一个工具栏上,而不是其他工具栏所在的停靠站点。 我通过将工具栏从其停靠的工具栏中移除并添加到停靠中来解决了问题。 因此,导致问题的安排是:

Dock 
  Toolbar 1
    Control 1
    Control 2
    Toolbar 2
      Control 3
      Control 4

修复方法是将它们排列如下:

Dock 
  Toolbar 1
    Control 1
    Control 2
  Toolbar 2
    Control 3
    Control 4

尽管如此,这仍然指向了TB2k代码中的一个错误 - 人们会认为它应该能够处理嵌套工具栏。


这似乎不是正常的行为,除非时间不对(所有者本身仍在创建过程中)。您何时/何地加载工具栏的设置? - Andriy M
只有在迭代开始之前已确定项目数量的情况下才使用for循环。当你不知道循环需要多少次迭代时,使用whilerepeat。在每次迭代之后(并且至少进行了一次迭代)重复检查条件,并在每次迭代之前使用while来检查条件(可能没有任何迭代)。 - Jørn E. Angeltveit
@Andy - 加载INI文件设置的调用是从初始化例程中进行的,该例程又从DPR(主程序)中调用,在所有表单创建完成后才会运行Application.Run。即使主窗体尚未完成创建,我也不希望组件计数减少。 - rossmcm
@Jørn -(代码属于Jordan Russell),我猜他期望所有者组件列表在循环期间大小保持不变。如果是这种情况,那么for...to循环是适当的。在一般情况下,如果有东西可以“进入”并在循环执行期间从列表中删除项目(看起来必须发生这种情况),那么我猜除了在每个引用之前进行显式检查之外,您无法保护对组件列表的访问。 - rossmcm
@Andriy - 我拼错了你的名字... - rossmcm
@rossmcm: 嗯,那对我来说听起来不错,我也不指望计数会改变。到目前为止,它似乎超出了我的专业水平,抱歉。 - Andriy M
2个回答

6
除了Lieven的答案之外,您也可以使用debug dcu,并在进入循环之前在TComponent.Destroy中设置一个断点。
在这两种情况下,您需要检查调用堆栈以查看count的调用/更改来自哪里。
Cary Jensen撰写了一篇非常有趣的关于断点的文章:http://caryjensen.blogspot.com/2010/08/breakpoints-with-side-effects.html

更好的方法是:在TComponent.Notification中设置断点;这将跟踪错误,即使组件未被销毁,但仅从主窗体的组件列表中删除。 - Ritsaert Hornstra
根据@Lieven的评论,我在TComponent.Remove开始之前设置了断点,然后它就触发了。现在只需要弄清楚为什么Jordan的代码在读取设置时会移除组件。我认为它与停靠有关,但我还没看出来... - rossmcm
@rossmcm - 很好发现,你可能想向TB2K的Jordan Russel报告此事。 - Marjan Venema

3

每当计数改变时,您需要在@Self.FComponents.FCount处添加一个数据断点以中断程序。

  • ComponentCount是一个属性,它返回从GetComponentCount获得的值。
  • GetComponentCount返回FComponents.Count
  • FComponents是一个TList实例,具有私有变量FCount

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接