I have StringGrid with 2 columns: Player and Scores. I have to sort this table looking at the score of a player.

This is the situation. I have tried with a StringGrid3.SortColRow(true, 1); but it sorts only the string value. If I have numbers like [1, 4, 12, 3] the sorted StringGrid becomes [a, 12, 3, 4].
I have to sort the Integer value, not the string one. Also, my problem is that I must move the player's name too with the numbers (as you can see in the picture above).
How could I do it?
You might write a comparator which is trying to sort by Numbers if both compared values are numbers. With casting the Stringgrid to its ancestor TCustomgrid you are able to use the procedure MoveRow to swap rows. An example showing sorting over many columns could look like this:
unit StringGridSortEnh;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, StdCtrls;
type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
type
  TMoveSG = class(TCustomGrid);
  TSortInfo = Record
    col: Integer;
    asc: Boolean;
  End;
function CompareNumber(i1, i2: Double): Integer;
// Result: -1 if i1 < i2, 1 if i1 > i2, 0 if i1 = i2
begin
  if i1 < i2 then
    Result := -1
  else if i1 > i2 then
    Result := 1
  else
    Result := 0;
end;
// Compare Strings if possible try to interpret as numbers
function CompareValues(const S1, S2 : String;asc:Boolean): Integer;
var
  V1, V2 : Double;
  C1, C2 : Integer;
begin
  Val(S1, V1, C1);
  Val(S2, V2, C2);
  if (C1 = 0) and (C2 = 0) then  // both as numbers
     Result := CompareNumber(V1, V2)
  else  // not both as nubers
     Result := AnsiCompareStr(S1, S2);
  if not Asc then Result := Result * -1;
end;
procedure SortGridByCols(Grid: TStringGrid; ColOrder: array of TSortInfo; Fixed: Boolean);
var
  I, J, FirstRow: Integer;
  Sorted: Boolean;
  function Sort(Row1, Row2: Integer): Integer;
  var
    C: Integer;
  begin
    C := 0;
    Result := CompareValues(Grid.Cols[ColOrder[C].col][Row1], Grid.Cols[ColOrder[C].col][Row2],ColOrder[C].asc);
    if Result = 0 then
    begin
      Inc(C);
      while (C <= High(ColOrder)) and (Result = 0) do
      begin
        Result := CompareValues(Grid.Cols[ColOrder[C].col][Row1], Grid.Cols[ColOrder[C].col][Row2],ColOrder[C].asc);
        Inc(C);
      end;
    end;
  end;
begin
  for I := 0 to High(ColOrder) do
    if (ColOrder[I].col < 0) or (ColOrder[I].col >= Grid.ColCount) then
      Exit;
  if Fixed then
    FirstRow := 0
  else
    FirstRow := Grid.FixedRows;
  J := FirstRow;
  Sorted := True;
  repeat
    Inc(J);
    for I := FirstRow to Grid.RowCount - 2 do
      if Sort(I, I + 1) > 0 then
      begin
        TMoveSG(Grid).MoveRow(i + 1, i);
        Sorted := False;
      end;
  until Sorted or (J >= Grid.RowCount + 1000);
  Grid.Repaint;
end;
procedure TForm1.Button1Click(Sender: TObject);
const // we want to use only 4 columns
  MyArray: array[0..3] of TSortInfo =
    ((col: 1; asc: true),
     (col: 2; asc: true),
     (col: 3; asc: true),
     (col: 4; asc: false)
     );
begin
  SortGridByCols(StringGrid1,MyArray,true);
end;
procedure TForm1.Button2Click(Sender: TObject);
const  // we want to use only one column
  MyArray: array[0..0] of TSortInfo = ((col: 1; asc: true));
begin
  SortGridByCols(StringGrid1,MyArray,true);
end;
end.


In Lazarus you can define how the cells of a TStringGrid sort using the OnCompareCells event, see the following link for and example of how to do this with numbers and more info.
http://wiki.lazarus.freepascal.org/Grids_Reference_Page#Sorting_Columns_or_Rows
If you want to sort the rows in Delphi you would need to re-implement the SortColRow method from Lazarus.
You can do this with a class helper
Note that this has NOT been tested fully!
The AnsiCompareStr in the below procedures can then be swamped out to compare integers.
type
  TStringGridHelper = class helper  for TStringGrid
  public
    procedure SortColRow(IsColumn: Boolean; Index: Integer); overload;
    procedure SortColRow(IsColumn: Boolean; Index: Integer; FromIndex: Integer; ToIndex: Integer); overload;
end;
implementation
procedure TStringGridHelper.SortColRow(IsColumn: Boolean; Index: Integer);
begin
     if (IsColumn) then SortColRow(IsColumn, Index, FixedCols, ColCount - 1)
     else SortColRow(IsColumn, Index, FixedRows, RowCount - 1)
end;
procedure TStringGridHelper.SortColRow(IsColumn: Boolean; Index: Integer; FromIndex: Integer; ToIndex: Integer);
    var i, p, x, c : Integer;
    s1, s2 : String;
begin
    if (IsColumn) then
    begin
        for x := ToIndex downto FromIndex do
            for I := FromIndex to ToIndex - 1 do
            begin
                s1 := Cells[i, index];
                s2 := Cells[i + 1, index];
                c := AnsiCompareStr(s1, s2);
                if (c > 0) then
                begin
                    p := i + 1;
                    p := Max(p, FromIndex);
                    p := Min(p, ToIndex);
                    MoveColumn(i, p);
                end;
            end;
    end
    else
    begin
        for x := ToIndex downto FromIndex do
            for I := FromIndex to ToIndex - 1 do
            begin
                s1 := Cells[index, i];
                s2 := Cells[index, i + 1];
                c := AnsiCompareStr(s1, s2);
                if (c > 0) then
                begin
                    p := i + 1;
                    p := Max(p, FromIndex);
                    p := Min(p, ToIndex);
                    MoveRow(i, p);
                end;
            end;
    end;
end;
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With