gpt4 book ai didi

delphi - TListView:如果添加列,VCL 会丢失列的顺序

转载 作者:行者123 更新时间:2023-12-03 15:00:19 25 4
gpt4 key购买 nike

我正在尝试在 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 源代码对于我的项目来说不是解决方案。已报告错误。

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

更新:reported bug现已关闭,从 Delphi XE2 Update 4 开始已修复.

最佳答案

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

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



更新:

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

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

  • 在 VCL 窗体上放置一个 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';
  • 运行项目并将“col 3”的列标题拖动到“col 1”和“col 2”之间。下图是您此时所看到的(一切都很好):

    list view after column drag

  • 点击按钮添加新列,现在 ListView 变为:

    list view after adding column

    请注意,“单元格 2”已恢复其原始位置。

错误:

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

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

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 ListView 控件中删除所有列,然后重新插入它们。请注意代码如何为每个插入列的 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”的修改副本放入您的项目文件夹中。否则,您可能会寻求运行时代码修补,或提交错误报告并等待修复。

关于delphi - TListView:如果添加列,VCL 会丢失列的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8258386/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com