在Delphi中,在THeadercontrol上调用Flip Children会引发错误

时间:2014-02-04 11:38:22

标签: delphi delphi-2010 delphi-6

我刚刚遇到Delphi中的一个行为,这对我来说似乎是个错误。

在Delphi中,只需在表单上删除 THeaderControl ,并为其分配至少一个部分。如果在当前表单上调用 FlipChildren(true),则会引发“列表索引越界”错误。看起来TCustomHeaderControl的FlipChildren过程中存在问题。

由于在各种版本的Delphi中我可以重现相同的行为(我已经尝试过Delphi 6和Delphi 2010),我有点不愿意将这个行为归类为bug。其他人之前遇到过这个问题吗?

1 个答案:

答案 0 :(得分:2)

这绝对是一个错误。我希望代码在Delphi 1中起作用,但THeaderSections的实现以破坏它的方式发生了变化。从那时起,你似乎是第一个执行代码的人!

以下是代码:

procedure TCustomHeaderControl.FlipChildren(AllLevels: Boolean);
var
  Loop, FirstWidth, LastWidth: Integer;
  ASectionsList: THeaderSections;
begin
  if HandleAllocated and
     (Sections.Count > 0) then
  begin
    { Get the true width of the last section }
    LastWidth := ClientWidth;
    FirstWidth := Sections[0].Width;
    for Loop := 0 to Sections.Count - 2 do Dec(LastWidth, Sections[Loop].Width);
    { Flip 'em }
    ASectionsList := THeaderSections.Create(Self);
    try
      for Loop := 0 to Sections.Count - 1 do with ASectionsList.Add do
        Assign(Self.Sections[Loop]);
      for Loop := 0 to Sections.Count - 1 do
        Sections[Loop].Assign(ASectionsList[Sections.Count - Loop - 1]);
    finally
      ASectionsList.Free;
    end;
    { Set the width of the last Section }
    if Sections.Count > 1 then
    begin
      Sections[Sections.Count-1].Width := FirstWidth;
      Sections[0].Width := LastWidth;
    end;
    UpdateSections;
  end;
end;

我们的想法是构建一个标题部分的临时列表,从真实部分中分配属性。然后以相反的顺序遍历临时列表,分配回标题部分的真实列表。但它不起作用。

整个代码都是假的,因为实际上只涉及一个集合。与控件关联的集合。 THeaderSections的设计假定标题控件和THeaderSections对象之间存在一对一的关系。可以很容易地观察到,ASectionsList.Add实际上会将项目添加到SectionsList

因此,当此代码完成运行时

for Loop := 0 to Sections.Count - 1 do with ASectionsList.Add do
  Assign(Self.Sections[Loop]);

您会发现Sections.Count已加倍,ASectionsList.Count仍为零。那么当我们继续运行时

for Loop := 0 to Sections.Count - 1 do
  Sections[Loop].Assign(ASectionsList[Sections.Count - Loop - 1]);

ASectionsList[Sections.Count - Loop - 1]的访问权限超出范围。

代码非常糟糕。我对此感到震惊。所需要的只是一个包含宽度的简单整数数组。以下是它应该看起来的样子,用插入器实现:

type
  THeaderControl = class(Vcl.ComCtrls.THeaderControl)
  public
    procedure FlipChildren(AllLevels: Boolean); override;
  end;

procedure THeaderControl.FlipChildren(AllLevels: Boolean);
var
  Index, Count: Integer;
  Widths: TArray<Integer>;
begin
  Count := Sections.Count;
  if Count>1 then
  begin
    SetLength(Widths, Count);
    for Index := 0 to Count-2 do
      Widths[Index] := Sections[Index].Width;
    Widths[Count-1] := ClientWidth;
    for Index := 0 to Count-2 do
      dec(Widths[Count-1], Widths[Index]);
    Sections.BeginUpdate;
    try
      for Index := 0 to Sections.Count-1 do
        Sections[Index].Width := Widths[Count-Index-1];
    finally
      Sections.EndUpdate;
    end;
  end;
end;

我建议您提交质量控制报告。