【问题标题】:Argument Out of Range issues using FMX TListBox使用 FMX TListBox 的参数超出范围问题
【发布时间】:2015-10-24 02:40:27
【问题描述】:

我在 Firemonkey 中使用 TListBox,在动态显示/隐藏项目时遇到了一个奇怪的问题。这包括德尔福 XE7 和 XE8。设置,在表单顶部有一个TPopupBox,用户在其中选择列出的项目之一。根据所选择的,TListBox 应该只显示某些TListBoxItems,并隐藏其余部分。其中一部分包括在不可见时将每个列表项的高度调整为 0(否则会在项目之间留下难看的间隙)。

问题在于,非常随机且自发地(无模式)在此 TPopupBox 中选择一个项目(调用 OnChange 修改可见性)会在未知点产生 EArgumentOutOfRangeException。代码在第一行调用CheckItemRangeInline(AIndex); 中的System.Generics.Collections.TListHelper.SetItemN() 中断,在那里,它很简单:

procedure TListHelper.CheckItemRangeInline(AIndex: Integer);
begin
  if (AIndex < 0) or (AIndex >= FCount) then
    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
end;

异常继续一遍又一遍地引发,没有结束(从连续 4 个开始)。当我使用调试器介入时,我永远无法让它发生。

这里使用了几个常用的过程来控制项目的可见性:

//lstTrans = TListBox

//Iterates through all items and hides everything
procedure TfrmMain.HideTransItems;
var
  X: Integer;
begin
  for X := 0 to lstTrans.Count-1 do begin
    lstTrans.ListItems[X].Visible:= False;
  end;
end;

//Sets height of visible items to 42, invisible items to 0
procedure TfrmMain.ResetTransHeights;
var
  X: Integer;
  LI: TListBoxItem;
begin
  for X := 0 to lstTrans.Count-1 do begin
    LI:= lstTrans.ListItems[X];
    if LI.Visible then
      LI.Height:= 42
    else
      LI.Height:= 0;
  end;
end;
然后,在选择@ 987654333中的某些内容时:
//cboTrans = TPopupBox

procedure TfrmMain.cboTransChange(Sender: TObject);
  procedure E(AItem: TListBoxItem);
  begin
    AItem.Visible:= True;
  end;
begin
  HideTransItems; //Make all list items invisible
  case cboTrans.ItemIndex of
    0: begin
      E(lbSomeListBoxItem);
      E(lbSomeOtherItem);
      //More calls to "E"
    end;
    1: begin
      E(lbSomeListBoxItem2);
      //More calls to "E"
    end;
    //More indexes
  end;
  ResetTransHeights; //Adjust visible list item heights to be seen
end;

(完整的过程只是很多完全相同类型的调用,这里就不多说了)

  1. 我没有在任何地方添加或删除项目 - 只是更改可见性
  2. 没有触发可能导致某些错误循环的事件
  3. TPopupBox 位于TListBox 之外
  4. 每个TListBoxItem 都有一个或两个控件(但显示/隐藏哪些控件并不重要)
  5. 在此 TPopupBox 中选择一个项目可能一次可行,但下一次失败
  6. 有时它会在我第一次显示/隐藏这些项目时发生,有时需要 20-30 次尝试
  7. 在调试中单步执行时无法重现

为什么我会收到此异常,我该如何解决?

【问题讨论】:

  • 您是否对 D10Seattle 进行了同样的尝试? TList 中存在一些错误。
  • 更多关于 TList 中错误的信息:plus.google.com/103246155735524926641/posts/Yne5Nv6mp6B
  • @LURD 我还没有尝试过 10,但是当我开始遇到这个问题时,我最初是在 XE7 中工作的。 TList&lt;T&gt; 错误显然出现在 XE8 中。
  • 一个看起来有效的丑陋解决方法是,我没有将高度设置为0,而是将它们设置为0.01
  • 几个小时没有问题后,我将其改回0,然后又开始了。否则这里根本没有模式。

标签: delphi listbox delphi-xe7 delphi-xe8


【解决方案1】:

为什么我会收到此异常,我该如何解决?

您知道收到它的原因。您正在访问一个索引超出有效范围的数组。

问题是该索引在哪里。如果您无法轻松重现,则需要调试以收集诊断信息。在 Windows 上,您可以使用 madExcept 之类的工具来收集信息。最有用的是导致错误的调用堆栈。

如果您手头没有 madExcept 或类似工具,请使用跟踪日志记录。检测您的代码,以便它记录允许您确定列表的哪些访问超出范围的信息。当您缩小搜索范围时,您可能最终会围绕这个进行迭代。

最后,一旦您确定导致错误的代码,通常问题就会变得明显。

【讨论】:

    【解决方案2】:

    我在为 TListBoxItem 的高度设置动画时遇到了同样的问题。 仅当我更改 Selected 项目的 Height 时才会出现此问题。我实现了Jerry Dodge's 解决方案,将高度设置为 0.01 而不是 0,从而解决了这个问题。

    德尔福柏林代码

        {Delphi Berlin}
        ItemIndex := 0;
        Item      := ListBox.ItemByIndex(ItemIndex);
        Height    := Item.Height;
    
        FloatAnimation              := TFloatAnimation.Create(nil);
        FloatAnimation.Parent       := Item;
        FloatAnimation.PropertyName := 'height'
        FloatAnimation.StartValue   := Height;
        FloatAnimation.StopValue    := 0.01; {Setting to 0 causes "Argument out of range" if the item is selected}
        FloatAnimation.Start;
    

    【讨论】:

      猜你喜欢
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 2021-07-11
      相关资源
      最近更新 更多