Group Items in Delphi's TListView Control

 By Zarko Gajic,

 

The TListView Delphi control displays and manages a list of items, displayed in columns, vertically or horizontally, with small or large icons.

Windows XP, and later versions, support grouping items in a list view. With the grouping feature of the ListView control, related sets of items can be displayed in groups. Groups are separated on the screen by horizontal group headers that contain the group titles.

Up until Delphi 2009, groups are not directly supported by the implementation of the TListView control.

 

Grouping Items in a TListView


If you are using Delphi 2007, Delphi 7 or any other previous version, you can also have grouping functionality in the TListView control.
The idea is to mimic item grouping with expandable and collapsible group items.

We'll hijack the Data property of the TListItem object. Items in a list view are presented by a TListItem object - used to specify the caption of the item, its glyph and other visual (and behavior) elements. The Data property specifies any application-specific data associated with the list item.

Note that the grouping implementation presented here leaves enough space for customization for your application-specific needs.

To follow along, have a ListView control on a form displaying its items in details view (ViewSytle = vsReport).

 

For the sake of simplicity we'll have two columns ("title" and "value") in the list view.
Download the sample project

 

Each list item will be assigned with a custom object, either a TGroupItem or a TItem. The TGroup item holds a group of TItem items. Group items can be expanded or collapsed to show or hide their "sub-items".

Normal list view items will be described with a TItem class:

TItem = class
private
  fTitle: string;
  fValue: string;
public
  constructor Create( const title, value : string) ;
   property Title: string read fTitle;
   property Value : string read fValue;
end;

An item that will be used to hold a collection of items is described by the TGroupItem class:

TGroupItem = class
private
  fItems : TObjectList;
  fCaption: string;
  fListItem: TListItem;
  fExpanded: boolean;
   function GetItems: TObjectList;
public
   constructor Create( const caption : string; const numberOfSubItems : integer) ;
  destructor Destroy; override;

   procedure Expand;
   procedure Collapse;

   property Expanded : boolean read fExpanded;
   property Caption : string read fCaption;
   property Items : TObjectList read GetItems;
   property ListItem : TListItem read fListItem write fListItem;
end;

The FillListViewGroups adds items to the list view:

procedure TForm1.FillListViewGroups;

   procedure AddGroupItem(gi : TGroupItem) ;
   var
    li : TListItem;
   begin
    li := lvGroups.Items.Add;

    li.Caption := gi.Caption;
    li.ImageIndex := 1; //collapsed

    li.Data := gi;
    gi.ListItem := li; //link "back"
   end;
begin
  ClearListViewGroups;

  AddGroupItem(TGroupItem.Create('Group A', 3)) ;
  AddGroupItem(TGroupItem.Create('Group B', 1)) ;
  AddGroupItem(TGroupItem.Create('Group C', 4)) ;
  AddGroupItem(TGroupItem.Create('Group D', 5)) ;
end;

A list item is added to the list view with its Data property pointing to an instance of a TGroupItem.

In the constructor we add dummy sub-items:

constructor TGroupItem.Create( const caption: string; const numberOfSubItems : integer) ;
var
  cnt : integer;
begin
  fCaption := caption;

   for cnt := 1 to numberOfSubItems do
   begin
    Items.Add(TItem.Create(caption + ' item ' + IntToStr(cnt), IntToStr(cnt))) ;
   end;
end;

Note that each TItem object added to the Items property of the TGroupItem will be presented as a normal list view item in the list view. Next, we need the functionality to expand or collapse groups. The OnDblClick event of the TListView control is used to handle this:

//handles TListView OnDblClick event
procedure TForm1.lvGroups DblClick(Sender: TObject) ;
var
  hts : THitTests;
  gi : TGroupItem;
begin
  hts := lvGroups.GetHitTestInfoAt(lvGroups.ScreenToClient(Mouse.CursorPos).X, lvGroups.ScreenToClient(Mouse.CursorPos).y) ;

   if (lvGroups.Selected <> nil) then
   begin
     if TObject(lvGroups.Selected.Data) is (TGroupItem) then
     begin
      gi := TGroupItem(lvGroups.Selected.Data) ;

       if NOT gi.Expanded then
        gi.Expand
       else
        gi.Collapse;
     end;
   end;
end;

The selected (double clicked) list view item is determined using the GetHitTestInfoAt method, if the list item is a "group item" the Expand or Collapse method is called.

Expand method will display sub-items, collapse will "hide" sub-items.

Here's the Expand method:

procedure TGroupItem.Expand;
var
  cnt : integer;
  item : TItem;
begin
  if Expanded then Exit;

  ListItem.ImageIndex := 0;
  fExpanded := true;

  for cnt := 0 to -1 + Items.Count do
  begin
    item := TItem(Items[cnt]) ;
    with TListView(ListItem.ListView).Items.Insert(1 + cnt + ListItem.Index) do
    begin
      Caption := item.Title;
      SubItems.Add(item.Value) ;
      Data := item;
      ImageIndex := -1;
    end;
  end;
end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值