使用FMX TListBox参数超出范围问题

时间:2015-10-24 02:40:28

标签: delphi listbox delphi-xe7 delphi-xe8

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

问题是非常随机且自发地(没有模式),选择此TPopupBox中的项目(调用OnChange修改可见性),在未知点产生EArgumentOutOfRangeException。代码在调用System.Generics.Collections.TListHelper.SetItemN()的第一行的CheckItemRangeInline(AIndex);处中断,其中只是:

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;

然后,在TPopupBox

中选择某些内容时
//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. 之外
  5. 每个TListBoxItem都有一个或两个控件(但显示/隐藏哪些控件并不重要)
  6. 选择此TPopupBox中的项目可能会有效,但下一次
  7. 会失败
  8. 有时会在我第一次显示/隐藏这些项目时出现,有时需要20-30次尝试
  9. 在调试
  10. 中单步执行时无法重现

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

2 个答案:

答案 0 :(得分:1)

  

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

你知道为什么要收到它。您正在访问索引位于有效范围之外的数组。

问题在于该指数在哪里。如果您无法轻松重现,则需要进行调试以收集诊断信息。在Windows上,您将使用像madExcept这样的工具来收集信息。最有用的是导致错误的调用堆栈。

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

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

答案 1 :(得分:0)

当我设置TListBoxItem的高度时,我遇到了同样的问题。 该问题仅发生在我更改 所选 项目的高度时。我实现了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;