Group Items in Delphi's TListView Control

来源:互联网 发布:淘宝红包口令 编辑:程序博客网 时间:2024/06/06 00:21

 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.lvGroupsDblClick(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

原创粉丝点击