【问题标题】:Deleting all components of a certain class on a form (Delphi)删除表单上某个类的所有组件(Delphi)
【发布时间】:2010-10-07 01:21:06
【问题描述】:

这可能是一个愚蠢的问题,但我的大脑已经足够成熟了,我想我将使用我的一条“生命线”来看看我是否可以从堆栈溢出的朋友那里获得一些帮助。 ;)

我需要在我的主窗体上删除所有出现的特定组件类型(其中一些在面板或标签页内,但都在同一个窗体上并归同一个窗体所有)。这是我现在拥有的:

for i := 0 to frmMain.ComponentCount - 1 do  
  begin  
    if frmMain.Components[i] is TMyClass then frmMain.Components[i].Destroy;  
  end;    

问题是(我在编译之前就知道会这样)一旦我销毁组件,表单的组件列表会重新索引,最终会超出范围。

解决这个问题的最佳方法是什么?我考虑将“找到”的组件添加到一个独立的数组中,然后在这个循环之后遍历它以删除它们,我认为这会起作用....但这是最好的方法吗?

TIA


更新:

你们摇滚。谢谢。 :)

【问题讨论】:

    标签: delphi forms components


    【解决方案1】:

    你几乎是对的。你的循环应该是这样的

    for i := frmMain.ComponentCount - 1 downto 0 do
    begin
      if frmMain.Components[i] is TMyClass then
        frmMain.Components[i].Free;
    end;
    

    这样对函数“frmMain.ComponentCount”的调用会在开始时完成,而不是再次完成。

    你也应该像上面那样调用 Free,而不是 Destroy——我现在不记得为什么了。 布里

    【讨论】:

    • 销毁是虚拟的。如果对象已经被销毁,那么它将失败。在调用 Destroy 之前免费检查它是否具有有效的引用。在这里可能不是问题,但总体上是一种很好的做法。
    • 在这种情况下,调用 Destroy 是安全的。由于 VCL 管理此列表的方式,该列表中不太可能存在无效引用。即使有,Free 也不会保护你,因为它依赖于 nil 实例。
    • 还要注意循环从高到零,以确保考虑所有项目,否则循环可以跳过已删除项目旁边的项目。重要的是不要错过。
    • 获得相同效果的另一种方法是将frmMain.ComponentCount-1 放入变量中。
    【解决方案2】:

    从顶部开始,向后工作。

    即:

    for i := frmMain.ComponentCount - 1 downto 0 do
    begin
      if frmMain.Components[i] is TMyClass then frmMain.Components[i].Free;
    end; 
    

    调用免费而不是销毁。免费调用检查有效参考后销毁。

    【讨论】:

    • 他也应该调用 Free 而不是 Destroy。永远不要调用 Destroy,而永远调用 Free。
    【解决方案3】:

    在您的情况下可能不会发生这种情况,但if frmMain.Components[i] is TMyClass 检查也会为 TMyClass 的后代类返回 true。如果你真的想删除一个特定的类,你可能需要额外检查ClassName

    【讨论】:

      【解决方案4】:

      使用 while 循环的相同解决方案:

      i := 0;
      while i < frmMain.ComponentCount do
      begin
        if frmMain.Components[i] is TMyClass then
          frmMain.Components[i].Free 
        else
          inc(i);
      end;
      

      【讨论】:

      • 这不起作用 - (i) 正在上升,而 (frmMain.ComponentCount) 正在下降
      • 如果你再看一眼,你会发现如果 componentcount 下降,我想上来。如果每个组件都属于 TMyClass 类,则 i 将保持为零,while 循环将终止,因为 0
      【解决方案5】:

      对于表单或面板中的精细控制可以使用此代码

      var
      
       i:Integer;
      
      begin
      
      for i := 0 to Panel1.ControlCount - 1 do
      
        begin
      
          if Panel1.Controls[i] is TEdit then
             Tedit(Panel1.Controls[i]).text := '';
      
        end;
      

      【讨论】:

        【解决方案6】:

        如果您需要检查和销毁命名的已知组件 使用

        If YourComponent <> Nil Then
          YourComponent.Free;
        

        【讨论】:

        • 这或多或少与if YourComponent &lt;&gt; nil then if YourComponent &lt;&gt; nil then YourComponent.Destroy; 相同,double if that 不合理,是吗? :-)
        猜你喜欢
        • 2021-08-26
        • 1970-01-01
        • 2014-09-30
        • 2021-12-04
        • 2010-09-08
        • 1970-01-01
        • 2011-03-27
        • 2020-08-26
        • 2016-04-24
        相关资源
        最近更新 更多