I have a VCL forms application, written in C Builder XE6, that contains a TListView
in Tile view.
Since the TListView
VCL component doesn't have a Tile view option, I use a TListView
with ViewStyle=vsReport
in the form designer and switch it to Tile view in code:
void __fastcall TForm1::FormShow (TObject *Sender)
{
TLVTileViewInfo tvi = {};
tvi.cbSize = sizeof(tvi);
tvi.dwMask = LVTVIM_COLUMNS;
tvi.cLines = ListView1->Columns->Count - 1;
ListView_SetTileViewInfo(ListView1->Handle, &tvi);
ListView_SetView(ListView1->Handle, LV_VIEW_TILE);
}
The TListView
also has Checkboxes=true
, GroupView=false
, RowSelect=true
, ShowWorkAreas=false
and SortType=stNone
.
The TListView
has the following OnInsert
event handler:
void __fastcall TForm1::ListView1Insert (TObject *Sender, TListItem *Item)
{
TLVTileInfo ti = {};
Item->Caption = " "; // ComCtl32.dll throws an access violation exception when caption is empty.
ti.cbSize = sizeof(ti);
ti.iItem = Item->Index;
ti.cColumns = ListView1->Columns->Count - 1;
ti.puColumns = new unsigned[ti.cColumns];
ti.piColFmt = new int[ti.cColumns];
try
{
for (unsigned i = 0; i < ti.cColumns; i )
{
ti.puColumns[i] = 1 i;
ti.piColFmt [i] = LVCFMT_LEFT;
}
ListView_SetTileInfo(ListView1->Handle, &ti);
}
__finally
{
delete[] ti.puColumns;
delete[] ti.piColFmt;
}
}
I insert an item into the TListView
, for example at the top:
TListItem* Item = ListView1->Items->Insert(0);
The item is inserted at the top of the list (Item->Index
is 0 after the insertion), but appears at the bottom of the list view on screen.
When I delete an item, the list view shows an empty space where the tile used to be. I fixed this with the following code after the deletion:
ListView_Arrange(ListView1->Handle, LVA_DEFAULT);
This removes the empty space from the list view.
Unfortunately, this has no effect when called after the insertion of an item. Newly inserted items remain displayed at the bottom of the list view.
If I insert an item into the list view in Report view, all works as expected. Just not when in Tile view.
How do I get the list view to display the items in the correct order (i.e. ascending order of the Index
property of the items) in Tile View?
Update
As it turns out, switching the view to any other type and back to LV_VIEW_TILE
causes the list view to arrange the items in the proper order.
This can be done after inserting the new item:
void __fastcall TForm1::Button1Click (TObject *Sender)
{
ListView1->Items->BeginUpdate(); // Disable repainting list view.
try
{
TListItem* Item = ListView1->Items->Insert(0);
Item->Caption = "New item";
ListView_SetView(ListView1->Handle, LV_VIEW_LIST); // Can be any LV_VIEW_... value other than LV_VIEW_TILE.
ListView_SetView(ListView1->Handle, LV_VIEW_TILE);
}
__finally
{
ListView1->Items->EndUpdate(); // Enable repainting list view.
}
}
CodePudding user response:
Try this code as a work around, does what you want and you won't even notice the switch from list to tile views.
void __fastcall TForm3::Button1Click(TObject *Sender)
{
ViewList(); // set ViewStyle to LV_VIEW_LIST
TListItem *item;
item = ListView1->Items->Insert(2); // insert it @ item index 2
// or ListView1->Items->Insert(ListView1->Selected->Index);
item->Caption = "Hello 1";
ViewTile(); // restore view to LV_VIEW_TILE
}
//---------------------------------------------------------------------------
void __fastcall TForm3::ViewTile()
{
//set view to Tile View
TLVTileViewInfo tvi = {};
tvi.cbSize = sizeof(tvi);
tvi.dwMask = LVTVIM_COLUMNS;
tvi.cLines = ListView1->Columns->Count - 1;
ListView_SetTileViewInfo(ListView1->Handle, &tvi);
ListView_SetView(ListView1->Handle, LV_VIEW_TILE);
}
//---------------------------------------------------------------------------
void __fastcall TForm3::ViewList()
{
// restore view to List View aka vsReport
TLVTileViewInfo tvi = {};
tvi.cbSize = sizeof(tvi);
tvi.dwMask = LVTVIM_COLUMNS;
tvi.cLines = ListView1->Columns->Count - 1;
ListView_SetTileViewInfo(ListView1->Handle, &tvi);
ListView_SetView(ListView1->Handle, LV_VIEW_LIST);
}
Add your ListView_Arrange(ListView1->Handle, LVA_DEFAULT); to your Delete1Click event of your popup menu (you already do that but shown here for others).
void __fastcall TForm3::Delete1Click(TObject *Sender)
{
ListView1->DeleteSelected();
ListView_Arrange(ListView1->Handle, LVA_DEFAULT);
}