我正在尝试在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源代码不是我的项目的解决方案。报道了Bug。
修改:删除了第一篇文章中无意中包含的第二个问题并打开了新问题(请参阅链接问题和问题修订版)。
更新:reported bug现已关闭,修正为Delphi XE2 Update 4。
答案 0 :(得分:7)
排列完列后调用UpdateItems
方法。 E.g:
..
col.Index := number;
listview.UpdateItems(0, MAXINT);
..
在我的测试中,我似乎仍然需要在某些场合使用上述电话。但真正的问题是“Delphi列表视图控件中存在错误”。
使用简单项目复制问题:
TListView
控件,将其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');
TButton
,并将以下代码放入其OnClick
处理程序:
ListView1.Columns.Add.Caption := 'col 4';
<强>错误:强>
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”的修改副本放到项目文件夹中。否则,您可能会进行运行时代码修补,或者提交错误报告并等待修复。