Link to home
Start Free TrialLog in
Avatar of Fatman121898
Fatman121898

asked on

StringGrid sorting

Does anyone knows some easy way to sort StringGrid Rows on a given Column's content?

Jo.
Avatar of Igor UL7AAjr
Igor UL7AAjr
Flag of Kazakhstan image

You may put all string from given columns to sorted TStringList and then back to StringGrids.

Cheers,
Igor.

PS: do not forget TStringList.Sorted:=true;
The sample

var L : TStringList;
begin
   L := TStringList.Create;
   L.Sorted:=true;
   L.Assign(StringGrid1.Cols[2]);
   StringGrid1.Cols[2].Assign(L);
   L.Free;
end;

---------
Igor
Avatar of Fatman121898
Fatman121898

ASKER

Hi Igor,

it's nice to hear you again.
What I'm trying is to sort whole stringgrid, not items in its rows separately.
That means to swap rows in such way that the values in key column are sorted in accendant (descendant) order.

Jo.
Hi Igor,

it's nice to hear you again.
What I'm trying is to sort whole stringgrid, not items in its rows separately.
That means to swap rows in such way that the values in key column are sorted in accendant (descendant) order.

Jo.
Hi,

bit more complex I think: you can copy the column you want to sort on to the first column. Then put all rows in a stringgrid. Sort it, remove the first column and then place it back (got idea from website).

have it working in programm, I also took those up-down arrows from Outlook and place them 'on' the grid when it's sorted.


getsort does the sorting, setImage switches between the images and in the mousedown event a leftclick in the header is detected. OmgekeerdResult is dutch for reversed-result.

some vars that I set on create:
//init globals
  omgekeerdResult := false;
  sortedOnColumn := 0; //invisible in UMS, so safe to set first
  globalWaitDblClick := false;
  globalCol := 0;
  globalRow := 0;
//init form
  imUp.visible := false;
  imDown.visible := false;
  imUp.parent := grdResult;
  imDown.parent := grdResult;
//vul grid a.d.h.v. sql
  grdResult.FixedRows := 1;
  grdResult.TopRow := 2;

with some copy-pasting you must be able to use my post, I expect...:-)

Floris.





procedure TResultaten.GetSort(var GenStrGrid : TStringGrid; ThatCol : Integer;omgekeerdResult : boolean);
{ Description : sort stringlist, by copying to stringlist
                (column that has to be sorted is move to beginning line, sort
                is done automatically and column is placed back)
  Pre         : rowcount has to be set correctly!
  Post        : genstrgrid sorted on Column:ThatCol
  Input       : -
  Returns     : -
  Creator     : Floris
  Date        : 5-2}
const
 TheSeparator = '@'; // Define the Separator
var
 CountItem, I, J, K, ThePosition : Integer;
 MyList : TStringList;
 MyString, TempString : String;
begin
  CountItem := GenStrGrid.RowCount; // Give the number of rows in the StringGrid
  MyList := TStringList.Create;//Create the List
  MyList.Sorted := False;
  try
    begin
    for I := 1 to (CountItem - 1) do
      begin
      MyList.Add(GenStrGrid.Rows[I].Strings[ThatCol] + TheSeparator + GenStrGrid.Rows[I].Text);
      end;
    Mylist.Sort;//Sort the List
    for K := 1 to Mylist.Count do
      begin
      MyString := MyList.Strings[(K - 1)];//Take the String of the line (K – 1)
      ThePosition := Pos(TheSeparator, MyString);//Find the position of the Separator in the String
      TempString := '';
      //element waarop gesorteerd is kan nu verwijderd worden van eerste positie
      TempString := Copy(MyString, (ThePosition + 1), Length(MyString));
      MyList.Strings[(K - 1)] := '';
      MyList.Strings[(K - 1)] := TempString;
      end;
   if not omgekeerdResult then
     begin
     for J := 1 to (CountItem - 1) do
       GenStrGrid.Rows[J].Text := MyList.Strings[(J - 1)];//Refill the StringGrid
     end
   else
     begin
     for J := 1 to (CountItem - 1) do
       GenStrGrid.Rows[J].Text := MyList.Strings[((CountItem-2)-(J - 1))];//Refill the StringGrid
     end;
   setImage(thatCol,omgekeerdResult); //plaats Outlookalike bitmap in columnheader.
  end;
 finally
  MyList.Free;//Free the List
 end;
end;

procedure TResultaten.setImage(thatCol: integer;down: boolean);
const
  distance = 20;
var
  MyLeft,y,z : integer;
begin
  y := grdResult.LeftCol;
  //loop column with till end thatCol
  myLeft := 0;
  for z := 0 to thatCol do
    myLeft := myLeft +grdResult.ColWidths[z];
  if not(down) then
    begin
    imUp.Left := (y+myLeft) - distance;
    imUp.Top := 1;
    imDown.visible := false;
    imUp.visible := true;
    end
  else
    begin
    imDown.Left := (y+myLeft) - distance;
    imDown.Top := 1;
    imUp.visible := false;
    imDown.visible := true;
    end
end;




procedure TResultaten.grdResultMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
{ Description : right and leftmouse handling, sort if column click.
  Pre         :
  Post        :
  Input       : -
  Returns     : -
  Creator     : Floris
  Date        : 3-2, update 4-2}

begin
if not (globalWaitDblClick) then //dubbel click was -> overslaan
  begin
  grdResult.MouseToCell(x,y,globalCol,globalRow);
  //right mouseclick
    if Button = mbright then
      begin
      if activeResultSet = false then //no activerestul, no pop-up at all.
        grdResult.popupMenu := nil
      else
        begin
  //      grdResult.MouseToCell(x,y,Col,Row); //HALELUJA! (wist niet dat deze functie bestond)
          if globalRow = -1 then
            exit
          else if globalRow = 0 then
            grdResult.popupMenu := popupTop //show popup for upper columns
          else
            begin
            grdResult.row := globalrow; //show normal popup and set current row here
            grdResult.popupMenu := popupGrid;
            end;
        end;
      end
  //left mouseclick
    else if (not (activeResultSet = false)) and (ssLeft in Shift) then
      begin
  //    grdResult.MouseToCell(x,y,Col,Row); //get row
      if globalRow = -1 then
        exit
      else if globalrow = 0 then
        begin
        screen.cursor := crHourGlass;
        //bepaal of er up of down gesort wordt.
        if (globalcol = sortedOnColumn) then
          begin
          if not omgekeerdResult then //switch after third clicks on same column
            omgekeerdResult := true
          else
            omgekeerdResult := false;
          end
        else
          omgekeerdResult := false;
        GetSort(grdResult,globalcol, omgekeerdResult);
        sortedOnColumn := globalcol;
        screen.cursor := crDefault;
        end;
      end;
  end
else
  globalWaitDblClick := false;
//grdResult.refresh; //how to refresh that move column line?
//grdResult.repaint;
end;
Hi Jo,
Hi floris (it's a comment!;)

Yes I'm wrong. Of course you need to sort whole stringgrid;) Just a moment, I have simply idea. TStringList can store not only strings but some associated data too. You may put as data number of original position in ROW. After sorting, it's possible to know where is new position. Just a moment, I will check it........


Igor.
Hi Floris,

This is not what I meant 'easy' ;-).
Anyway, I'll test it for a while, and be back soon.

Jo.
ASKER CERTIFIED SOLUTION
Avatar of Igor UL7AAjr
Igor UL7AAjr
Flag of Kazakhstan image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Igor, that is what I needed.
You got the points.
Floris, thank you too.

Jo.