Search code examples
iosdelphilistboxdelphi-xe6

Sorting listbox by user defined criteria - delphi xe6


I am trying to implement my own sorting feature for a Listbox. What I am wanting to do is, sort items within a listbox depending upon the chosen criteria, whether based on for example, criteria1,criteria2,criteria3... and so on.

I have these, lets call them randomObjects that act as records for the data. These random objects look like this:

type
  randomObject = class(TObject)
    ID,
    criteria1,
    criteria2,
    criteria3:String;
  end;

Here is the function I call when wanting to sort the randomObjects in the listbox:

procedure TmyForm.sortME(criteria: string; asc: Boolean);
var
  tempList,pList:TStringList;
  p:part;
  i:integer;
  item:TListBoxItem;
begin
  tempList := TStringList.Create;
  for p in AllRandomObjects do //allRandomObjects is an array of RandomObject
    if criteria = 'Criteria1' then
      tempList.Append(p.Criteria1)
    else if criteria = 'Criteria2' then
      tempList.Append(p.Criteria2)
    else if criteria = 'Criteria3' then
      tempList.Append(p.criteria3);

  Plist:= TStringList.Create; //pList to keep track of original order to reference the RandomObjects
  plist.Text := tempList.Text;
  if asc then
    tempList.Sorted:=true //create new order
  else
    tempList.CustomSort(StringListSortCompare); //create new order

  listbox.BeginUpdate;
  listbox.Items.Clear;
  for i := 0 to tempList.Count-1 do
  begin
    p := AllRandomObjects[plist.IndexOf(tempList.Strings[i])];
    Listbox.Items.Append('');
    item := Listbox.ListItems[Listbox.Items.Count-1];
    //blah-blah, create text objects to add to the item for displaying
    end;
  end;
  listbox.EndUpdate;

end;

This takes very long however ( at least a few seconds, which seems like forever when on mobile ). Just learning, I'm sure there is a better/faster/more efficient way of doing this. Please help or give guidance!. Thanks! Developing for iOS, FMX Delphi xe6


Solution

  • You should sort the array itself with System.Generics.Collections.TArray.Sort and iterate over the array to populate the data to the listbox.

    uses
      System.Generics.Collections,
      System.Generics.Defaults,
      System.StrUtils;
    
    procedure TmyForm.sortME( criteria: string; asc: Boolean );
    var
      LCriteriaIndex : Integer;
      LData : TList<randomObject>;
    begin
      LCriteriaIndex := IndexText( criteria, ['criteria1', 'criteria2', 'criteria3'] );
    
      if LCriteriaIndex < 0 then
        raise EArgumentException.Create( 'unknown criteria' );
    
      LData := TList<randomObject>.Create( TComparer<randomObject>.Construct(
            function( const L, R : randomObject ) : Integer
        begin
          case LCriteriaIndex of
            0 :
              Result := CompareText( L.criteria1, R.criteria1 ); 
            1 :
              Result := CompareText( L.criteria2, R.criteria2 );
            2 :
              Result := CompareText( L.criteria3, R.criteria3 );
          end;
    
          if not asc
          then
            Result := -Result;
        end ) );
    
      LData.AddRange( AllRandomObjects );
      LData.Sort;
    
      showData( LData.ToArray );
    end;
    
    procedure TmyForm.showData( AData : TArray<randomObject> );
    var
      LData : randomObject;
      LItem : TListBoxItem;
    begin
      listbox.BeginUpdate;
      try
        listbox.Clear;
        for LData in AData do
        begin
          LItem := TListBoxItem.Create( listbox );
    
          //blah-blah, create text objects to add to the item for displaying
    
          listbox.AddObject( LItem );
        end;
      finally
        listbox.EndUpdate;
      end;
    end;