6

我正在尝试在 TListView 中的现有列之间添加一列。因此,我在末尾添加新列并通过将其索引设置为指定值来移动它。这有效,直到添加另一个新列。

我所做的:在最后一个位置(Columns.Add)添加列,并在最后一个位置(Subitems.Add)添加子项。之后,我通过将列的索引设置到正确的位置来移动列。只要它只是添加一列,它就可以正常工作。添加第二个新列时,子项会搞砸。第一列的新子项移动到最后一个位置,例如这样:

0        |  1          |  new A       |  new B      | 3
Caption  |  old sub 1  |  old sub 3   |  new Sub B  | new sub A

如果有人可以提供帮助,我将非常高兴!

例如,是否有一个命令或消息我可以发送到 ListView 以便它刷新或保存它和第一个方法一样。

或者这只是 TListViews 列的错误--> 子项处理或 TListColumns ...?

vcl 表单应用程序的示例代码(分配 Form1.OnCreate 事件):

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    listview: TListView;
    initButton: TButton;
    addColumn: TButton;
    editColumn: TEdit;
    subItemCount: Integer;
    procedure OnInitClick(Sender: TObject);
    procedure OnAddClick(Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  listview := TListView.Create(self);
  with listview do
  begin
    Left := 8;
    Top := 8;
    Width := self.Width - 30;
    Height := self.Height - 100;
    Anchors := [akLeft, akTop, akRight, akBottom];
    TabOrder := 0;
    ViewStyle := vsReport;
    Parent := self;
  end;

initButton := TButton.Create(self);
with initButton do
  begin
    left := 8;
    top := listview.Top + listview.Height + 20;
    Width := 75;
    Height := 25;
    TabOrder := 1;
    Caption := 'init';
    OnClick := OnInitClick;
    Parent := self;
  end;

  editColumn := TEdit.Create(self);
  with editColumn do
  begin
    left := initButton.Left + initButton.Width + 30;
    top := listview.Top + listview.Height + 20;
    Width := 120;
    Height := 25;
    TabOrder := 2;
    Parent := self;
    Caption := '';
  end;

  addColumn := TButton.Create(self);
  with addColumn do
  begin
    left := editColumn.Left + editColumn.Width + 10;
    top := listview.Top + listview.Height + 20;
    Width := 75;
    Height := 25;
    TabOrder := 1;
    Enabled := true;
    Caption := 'add';
    OnClick := OnAddClick;
    Parent := self;
  end;

end;

procedure TForm1.OnInitClick(Sender: TObject);
var col: TListColumn;
i, j: integer;
item: TListItem;
begin
  listview.Items.Clear;
  listview.Columns.Clear;

  // add items
  for I := 0 to 2 do
  begin
    col := ListView.Columns.Add;
    col.Caption := 'column ' + IntToStr(i);
    col.Width := 80;
  end;

  // add columns
  for I := 0 to 3 do
  begin
    item := ListView.Items.Add;
    item.Caption := 'ItemCaption';

    // add subitems for each column
    for j := 0 to 1 do
    begin
      item.SubItems.Add('subitem ' + IntToStr(j+1));
    end;
  end;

  subItemCount := 5;
end;

procedure TForm1.OnAddClick(Sender: TObject);
var number: integer;
col: TListColumn;
i: Integer;
ascii: char;
begin
  listview.Columns.BeginUpdate;

  number := StrToInt(editColumn.Text);
  ascii :=  Chr(65 + number);

  // create the new column
  col := TListColumn(ListView.Columns.add());
  col.Width := 80;
  col.Caption := ascii;

  // add the new subitems
  for I := 0 to ListView.Items.Count-1 do
  begin
    ListView.Items[i].SubItems.Add('subitem ' + ascii);
  end;

  // move it to the designated position
  col.Index := number;

  listview.Columns.EndUpdate;

  Inc(subItemCount);
end;

end.

谢谢!


编辑:Sertac Akyuz 建议的修复工作正常,但我不能使用它,因为更改 Delphi 源代码对我的项目没有解决方案。报告错误。

编辑:删除了第一篇文章中无意包含的第二个问题并打开了新问题(请参阅链接问题和问题修订)。

更新报告的错误现在已关闭,与 Delphi XE2 Update 4一样已修复。

4

1 回答 1

7

UpdateItems排列好列后调用该方法。例如:

..
col.Index := number;
listview.UpdateItems(0, MAXINT);
..



更新:

在我的测试中,在某些情况下我似乎仍然需要上述调用。但真正的问题是“Delphi 列表视图控件中存在错误”

用一个简单的项目复制问题:

  • TListView在 VCL 表单上放置一个控件,将其设置ViewStyle为“vsReport”并设置FullDrag为“true”。
  • 将以下代码放入OnCreate表单的处理程序:
    ListView1.Columns.Add.Caption := 'col 1';
    ListView1.Columns.Add.Caption := 'col 2';
    ListView1.Columns.Add.Caption := 'col 3';
    ListView1.AddItem('cell 1', nil);
    ListView1.Items[0].SubItems.Add('cell 2');
    ListView1.Items[0].SubItems.Add('cell 3');
    
  • 将 aTButton放在表单上,​​并将以下代码放入其OnClick处理程序:
    ListView1.Columns.Add.Caption := 'col 4';
  • 运行项目并将“col 3”的列标题拖到“col 1”和“col 2”之间。下图是您此时将看到的(一切都很好):

    列拖动后的列表视图

  • 单击按钮添加新列,现在列表视图变为:

    添加列后的列表视图

    注意“单元格 2”已收回其原始位置。

漏洞:

TListView( )的列在其字段TListColumn中保存其排序信息。FOrderTag每当您更改列的顺序(通过设置Index属性或通过拖动标题)时,FOrderTag都会相应地更新。

现在,当您向TListColumns集合添加列时,集合首先添加新列TListColumn,然后调用该UpdateCols方法。下面是D2007 VCL中的UpdateCols方法代码:TListColumns

procedure TListColumns.UpdateCols;
var
  I: Integer;
  LVColumn: TLVColumn;
begin
  if not Owner.HandleAllocated then Exit;
  BeginUpdate;
  try
    for I := Count - 1 downto 0 do
      ListView_DeleteColumn(Owner.Handle, I);

    for I := 0 to Count - 1 do
    begin
      with LVColumn do
      begin
        mask := LVCF_FMT or LVCF_WIDTH;
        fmt := LVCFMT_LEFT;
        cx := Items[I].FWidth;
      end;
      ListView_InsertColumn(Owner.Handle, I, LVColumn);
      Items[I].FOrderTag := I;
    end;
    Owner.UpdateColumns;
  finally
    EndUpdate;
  end;
end;


上面的代码从底层 API 列表视图控件中删除所有列,然后重新插入它们。注意代码如何分配每个插入列的FOrderTag索引计数器:

      Items[I].FOrderTag := I;

这是该时间点从左到右的列顺序。如果每当列的排序与创建时不同时调用该方法,则该排序将丢失。而且由于物品没有相应地改变它们的位置,所以一切都变得混乱了。

使固定:

以下对该方法的修改似乎只适用于我测试的时间,您需要进行更多测试(显然此修复程序并未涵盖所有可能的情况,有关详细信息,请参阅下面的“torno 评论”):

procedure TListColumns.UpdateCols;
var
  I: Integer;
  LVColumn: TLVColumn;
  ColumnOrder: array of Integer;
begin
  if not Owner.HandleAllocated then Exit;
  BeginUpdate;
  try
    SetLength(ColumnOrder, Count);
    for I := Count - 1 downto 0 do begin
      ColumnOrder[I] := Items[I].FOrderTag;
      ListView_DeleteColumn(Owner.Handle, I);
    end;

    for I := 0 to Count - 1 do
    begin
      with LVColumn do
      begin
        mask := LVCF_FMT or LVCF_WIDTH;
        fmt := LVCFMT_LEFT;
        cx := Items[I].FWidth;
      end;
      ListView_InsertColumn(Owner.Handle, I, LVColumn);
    end;
    ListView_SetColumnOrderArray(Owner.Handle, Count, PInteger(ColumnOrder));

    Owner.UpdateColumns;
  finally
    EndUpdate;
  end;
end;

如果您不使用包,您可以将“comctrls.pas”的修改副本放入您的项目文件夹。否则,您可能会追求运行时代码修补,或提交错误报告并等待修复。

于 2011-11-24T15:59:17.587 回答