Search code examples
sortingdelphidelphi-xe2vcltlistview

Sorting ListView Groups?


In a ListView, the Items are grouped by the groups "BGroup", "CGroup" and "DGroup" (These are the group headers). Now, when I add a new Item to the ListView and assign a new group with the header "AGroup" to this Item, the group "AGroup" is always inserted at the end of the groups; so the new Groups order is: BGroup, CGroup, DGroup, AGroup. So how can I get the groups sorted in correct alphabetical order? The order should be: AGroup, BGroup, CGroup, DGroup.


Solution

  • You can use the ListView_SortGroups macro for this e.g. This macro expects from you to have your own comparison function, defined by the LVGroupCompare function prototype. In the following code the groups are sorted by the Header property by using the CompareText function, but now it's upon you to build your own comparison.

    Forgot to note; whatever you pass to the last Pointer type parameter of the ListView_SortGroups macro you'll receive in the LVGroupCompare function in the pvData parameter, so as this is going to be a group sorting function of a certain list view, it's the best to pass directly Groups collection of that list view for easier manipulation.

    Since there is no direct way to find a list view group by group ID, I'd use the following helper function for the TListGroups class:

    type
      TListGroups = class(ComCtrls.TListGroups)
      public
        function FindItemByGroupID(GroupID: Integer): TListGroup;
      end;
    
    implementation
    
    function TListGroups.FindItemByGroupID(GroupID: Integer): TListGroup;
    var
      I: Integer;
    begin
      for I := 0 to Count - 1 do
      begin
        Result := Items[I];
        if Result.GroupID = GroupID then 
          Exit;
      end;
      Result := nil;
    end;
    

    Then you can use this helper method in the LVGroupCompare function callback this way:

    function LVGroupCompare(Group1_ID, Group2_ID: Integer;
      pvData: Pointer): Integer; stdcall;
    var
      Item1: TListGroup;
      Item2: TListGroup;
      Groups: TListGroups;
    begin
      Result := 0;
      Groups := TListGroups(pvData);
      Item1 := Groups.FindItemByGroupID(Group1_ID);
      Item2 := Groups.FindItemByGroupID(Group2_ID);
      if Assigned(Item1) and Assigned(Item2) then
        Result := CompareText(Item1.Header, Item2.Header);
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Item: TListItem;
      Group: TListGroup;
    begin
      Group := ListView1.Groups.Add;
      Group.Header := 'AGroup';
    
      Item := ListView1.Items.Add;
      Item.Caption := 'Item X';
      Item.GroupID := Group.ID;
    
      ListView_SortGroups(ListView1.Handle, LVGroupCompare, ListView1.Groups);
    end;