2

我想我在 TListView 中发现了一个潜在的错误。

重现步骤:创建一个新的 VCL Forms 应用程序,添加一个 TListView,将其 ViewStyle 设置为 vsReports。添加两个按钮

按钮1:

procedure TForm1.Button1Click(Sender: TObject);
var
  lCol: TListColumn;
begin
  lcol :=   ListView1.Columns.Add;
  lcol.Caption := 'name';
  lcol :=   ListView1.Columns.Add;
  lcol.Caption := 'name2';
  lcol :=   ListView1.Columns.Add;
  lcol.Caption := 'name3';
end;

按钮2:

procedure TForm1.Button2Click(Sender: TObject);
begin
  ListView1.Columns.Delete(1);
end;

结果:该列被删除,但最后一列的标题丢失。当添加更多列并删除其他列之间的列(或删除第一列)时,也会发生这种情况。最后一列的标题始终为空。

我正在使用 XE3。有什么我错过的吗?

谢谢

编辑: 质量控制链接

潜在重复

4

2 回答 2

4

除了问题中报告的内容之外,还有更多内容(最后更多)。

这与您之前的问题有关。该问题涉及列表视图控件在添加列后移动列时丢失列和项/子项之间的映射。我提出了一个可能的解决方案,comctrls.pas其中涉及FOrderTag在移动列时保留 s 列。每当移动列时,VCL 都会从头开始构建“FOrderTag” - 不考虑列的当前位置。

然后发生的事情是,您提交错误报告,提交可能的修复作为解决方法,然后它会按原样签入。现在您发现的问题是,当我们保留FOrderTag每一列,然后从中间删除一列时,我们会创建一个洞 - 它们不再是连续的(假设我们有带有各自顺序标签的第 0、1 和 2 列,删除第 1 列,现在我们有 2 列,订单标签为 0 和 2)。显然本机控件不喜欢这样。

再次修改 VCL,我们可以在移除列时移除任何可能的孔。当您调整/移动问题评论中提到的缺少标题的列时,下面似乎会处理缺少的标题和 AV。

destructor TListColumn.Destroy;
var
  Columns: TListColumns;
  i: Integer; //+
begin
  Columns := TListColumns(Collection);
  if TListColumns(Collection).Owner.HandleAllocated then
    ListView_DeleteColumn(TListColumns(Collection).Owner.Handle, Index);
//{+
  for i := 0 to Columns.Count - 1 do
    if Columns[i].FOrderTag > FOrderTag then
      Dec(Columns[i].FOrderTag);
//}
  inherited Destroy;
  Columns.UpdateCols;
end;


现在,如果我们回到问题中未报告的内容,如果您插入了一些子项,您会注意到它们保留了它们的位置,IOW 列和子项之间的映射丢失了。您的观点可能与我的观点不同,但我认为已删除列的子项应该会丢失。不幸的是,我无法找到实现这一目标的方法。


编辑:我想不出任何可以在 VCL 中轻松集成/修复的东西。没有什么能阻止您删除第一个插入的列。这一项对应items,如果我们删除items,所有子item也会被取出。VCL 中的当前实现是,当您删除列时,实际上不会删除任何项目数据。您可以通过在删除一列后添加一列来验证这一点,子项将神奇地出现在新列下。

无论如何,我可以建议您手动删除已删除列的子项。以下是删除列及其相应子项的实用程序示例:

procedure ListViewDeleteColumn(ListView: TListView; Col: Integer);
var
  i: Integer;
  ColumnOrder: array of Integer;
begin
  SetLength(ColumnOrder, ListView.Columns.Count);
  ListView_GetColumnOrderArray(
        ListView.Handle, ListView.Columns.Count, PInteger(ColumnOrder));
  Assert(ColumnOrder[Col] <> 0, 'column with items cannot be removed');

  for i := 0 to ListView.Items.Count - 1 do
    if Assigned(ListView.Items[i].SubItems) and
        (ListView.Items[i].SubItems.Count >= Col) then
    ListView.Items[i].SubItems.Delete(ColumnOrder[Col] - 1);

  ListView.Columns.Delete(Col);
end;

如果您决定删除第一列,请决定您将如何处理项目/子项目并重建它们。

于 2012-09-21T02:11:31.090 回答
2

如果您使用下面的代码删除最后一列,则可以正常工作:

uses
 CommCtrl;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ListView_DeleteColumn(ListView1.Handle, 2);
end;
于 2012-09-20T13:51:48.417 回答