我刚刚遇到Delphi中的一个行为,这对我来说似乎是个错误。
在Delphi中,只需在表单上删除 THeaderControl ,并为其分配至少一个部分。如果在当前表单上调用 FlipChildren(true),则会引发“列表索引越界”错误。看起来TCustomHeaderControl的FlipChildren过程中存在问题。
由于在各种版本的Delphi中我可以重现相同的行为(我已经尝试过Delphi 6和Delphi 2010),我有点不愿意将这个行为归类为bug。其他人之前遇到过这个问题吗?
答案 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;
我建议您提交质量控制报告。