I think I found a potential bug in TListView.
Steps to reproduce: Create a new VCL Forms application, add a TListView, set it`s ViewStyle to vsReports. Add two buttons
button1:
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;
button2:
procedure TForm1.Button2Click(Sender: TObject);
begin
ListView1.Columns.Delete(1);
end;
Result: The column is deleted, but the caption of the last column gets lost. This also happens, when adding more columns and deleting a column that is between others (or deleting the first column). The caption of the last column is always empty.
I'm using XE3. Is there anything I missed?
Thanks
edit: QC link
There's more to this then what's reported in the question (more at the end).
This is related with a previous question of yours. That question involved the listview control losing the mapping between columns and items/subitems when you moved a column after adding a column. I proposed a possible fix for comctrls.pas
which involved preserving FOrderTag
s of columns when they are moved. The VCL had 'FOrderTag's built from the ground-up whenever a column is moved - disregarding any current positioning of the columns.
What happens then is, you file a bug report, submit the possible fix as a workaround, and it gets checked-in exactly as is. The problem now you discover is, when we preserve FOrderTag
of each column, and then remove a column from the middle, we create a hole - they are not sequential any more (say we have columns 0, 1 and 2 with respective order tags, remove column 1 and now we have 2 columns with order tags 0 and 2). Apparently the native control does not like this.
Again modifying the VCL, we can remove any possible hole when we are removing a column. The below seems to take care of the missing caption and the AV when you resize/move the column with the missing caption mentioned in a comment to the question.
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;
Now if we come back to what's not reported in the question, if you had been inserted some subitems, you'd have noticed that they are preserving their positions, IOW the mapping between columns and subitems are lost. There's the probability that your view is different then mine on this, but I think the subitems of the deleted column should get lost. Unfortunately I couldn't figure out a way to achieve this.
edit: I cannot think of anything to easily integrate/fix in the VCL. There's nothing stopping you from deleting the first inserted column. This one corresponds to the items, if we delete the items, all subitems will also be taken out. The current implementation in VCL is that in fact no item data is deleted when you remove a column. You can verify this by adding a column after you remove one, subitems will magically appear under the new column.
Anyway, what I can suggest you to is to delete the subitems of a removed column manually. Below is an example of a utility procedure to delete a column and its corresponding subitems:
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;
If you decide to delete the first column, decide what you'll do with items/subitems and rebuild them.