Search code examples
sortingdelphidelphi-xe2tstringgrid

Delphi - problem with string grid after sorting


So the string grid I have in the program I mentioned here: (Delphi - Changing active page's tab color and having it reset after clicking on another tab) sorts perfectly from smallest to largest but the grid glitches/goes haywire in a way. The sorted rows get thrown to the end of the grid (sometimes even without row numbers or the rows keep their numbers). So my problem is how can I sort my string grid without completely ruining the grid in the process?

Code I'm using:

//code that sorts the grid
procedure TfrmPuntehou.SortSTLGrid(var grid:TStringGrid; columntotal:integer);
const
separator = ',';
var
iCount,i,j,k,iPos:integer;
TheList:TStringList;
sString,sTempString:string;
begin
  //procedure to sort from small to large values

  //get row amount
  iCount:=grid.RowCount;

  //create list
  TheList:=TStringList.Create;
  TheList.Sorted:=False;

  //start of try..finally block
    try
    begin

      //fill the list
      for i := 1 to (iCount - 1) do
      begin
      TheList.Add(grid.Rows[i].Strings[columntotal]+separator+grid.Rows[i].Text);
      end;

      //sort the list
      TheList.Sort;

      for k := 1 to TheList.Count do
      begin
      //take the line of the list and put it in a string var
      sString:= TheList.Strings[(k-1)];
      //get separator pos in that string
      iPos:=AnsiPos(separator,sString);
      sTempString:='';
      //remove separator and the column text at the front of the string
      sTempString:=Copy(sString,(iPos+2),Length(sString));
      TheList.Strings[(k-1)]:= '';
      TheList.Strings[(k-1)]:= sTempString;
      end;

      //fill the grid
      for j:= 1 to (iCount - 1) do
      begin
      grid.Rows[j].Text := TheList.Strings[(J-1)] ;
      end;

    end;
    finally
    TheList.Free;
    end;
  //end of try..finally block

end;

//code that I use to customize the grid on startup

procedure TfrmPuntehou.TitlesAndNumbering(grid: TStringGrid);
var
  i:integer;
begin
  //procedure that customizes the grid entered as a parameter
  with grid do
  begin
    //names the columns
    Cells[0,0]:='Row Number';
    Cells[1,0]:='Car Number';
    Cells[2,0]:='Name';
    Cells[3,0]:='Licence';
    Cells[4,0]:='Heat 1';
    Cells[5,0]:='Heat 2';
    Cells[6,0]:='Subtotal 1';
    Cells[7,0]:='Heat 3';
    Cells[8,0]:='Subtotal 2';
    Cells[9,0]:='Final';
    Cells[10,0]:='Final Total';

        //for loop to number the rows
        for i := 1 to rowMax do
        begin
            Cells[0,i]:=IntToStr(i);
        end;
        //end of for

    //other extra settings
    RowCount:=rowMax;
    ColCount:=colMax;
    DefaultColWidth:=100;
    FixedCols:=0;
    FixedRows:=1;
  end;
end;

Screenshots to illustrate the problem:

Before sorting:
enter image description here

After sorting:
enter image description here

enter image description here

Thanks in advance for the help!
Kind Regards
PrimeBeat


Solution

  • To summarize an answer from comments:

    Your problem comes from the fact that you add a lot of empty rows because you set RowCount equal to RowMax. Once sorted, the empty cells goes to the top of the list.

    There are two solutions:

    1. You stop adding empty lines and sorting will be as expected
    2. Manage to sort with a comparer that makes empty string BIGGER as all other string instead of the default which is smaller. See the documentation for CustomSort

    Note that you can change the row count at anytime. Just assign the RowCount property. For example, when you add a row, do:

       Grid.RowCount := Grid.RowCount + 1;
    

    And when you remove the last line, do:

       Grid.RowCount := Grid.RowCount - 1;