2008. július 27., vasárnap

TStringGrid functions (Delete, Insert, Sort)


Problem/Question/Abstract:

How to insert, delete or sort columns in StringGrids

Answer:

Solve 1:

procedure GridRemoveColumn(StrGrid: TStringGrid; DelColumn: Integer);
var
  Column: Integer;
begin
  if DelColumn <= StrGrid.ColCount then
  begin
    for Column := DelColumn to StrGrid.ColCount - 1 do
      StrGrid.Cols[Column - 1].Assign(StrGrid.Cols[Column]);
    StrGrid.ColCount := StrGrid.ColCount - 1;
  end;
end;

procedure GridAddColumn(StrGrid: TStringGrid; NewColumn: Integer);
var
  Column: Integer;
begin
  StrGrid.ColCount := StrGrid.ColCount + 1;
  for Column := StrGrid.ColCount - 1 downto NewColumn do
    StrGrid.Cols[Column].Assign(StrGrid.Cols[Column - 1]);
  StrGrid.Cols[NewColumn - 1].Text := '';
end;

procedure GridSort(StrGrid: TStringGrid; NoColumn: Integer);
var
  Line, PosActual: Integer;
  Row: TStrings;
begin
  Renglon := TStringList.Create;
  for Line := 1 to StrGrid.RowCount - 1 do
  begin
    PosActual := Line;
    Row.Assign(TStringlist(StrGrid.Rows[PosActual]));
    while True do
    begin
      if (PosActual = 0) or (StrToInt(Row.Strings[NoColumn - 1]) >=
        StrToInt(StrGrid.Cells[NoColumn - 1, PosActual - 1])) then
        Break;
      StrGrid.Rows[PosActual] := StrGrid.Rows[PosActual - 1];
      Dec(PosActual);
    end;
    if StrToInt(Row.Strings[NoColumn - 1]) < StrToInt(StrGrid.Cells[NoColumn - 1,
      PosActual]) then
      StrGrid.Rows[PosActual] := Row;
  end;
  Renglon.Free;
end;


Solve 2:

Had a few problems with range errors with the algorythms. On Delete or Add columns it is desirable to keep the widths of the columns as they are moved. Add column could also take the width of the new column (or default to DefaultColWidth if zero). I also had range errors in the Grid sort. On a large grid a Quicksort routine would be more desirable.

The Quicksort routine could take various sort modes as a parameter eg. Alpha,Double,Integer etc. (have supported only these 3 in demo, but it's easy to see how to incorporate more). The quick sort should also take "from row - to row" as parameters as we normally would not want to sort the header, or just a sub range may be required to be
sorted.

All in all though, some nice ideas for an extended stringgrid class, couple with DeleteRow, AddRow, LoadFromQuery etc.

procedure RemoveColumn(SG: TStringGrid; ColNumber: integer);
var
  Column: integer;
begin
  ColNumber := abs(ColNumber);

  if ColNumber <= SG.ColCount then
  begin
    for Column := ColNumber to SG.ColCount - 2 do
    begin
      SG.Cols[Column].Assign(SG.Cols[Column + 1]);
      SG.Colwidths[Column] := SG.Colwidths[Column + 1];
    end;
    SG.ColCount := SG.ColCount - 1;
  end;
end;

procedure AddColumn(SG: TStringGrid; AtColNumber: integer;
  ColWidth: integer = 0);
var
  Column: integer;
  Wdth: integer;
begin
  AtColNumber := abs(AtColNumber);
  SG.ColCount := SG.ColCount + 1;
  if abs(ColWidth) = 0 then
    Wdth := SG.DefaultColWidth
  else
    Wdth := ColWidth;

  if AtColNumber <= SG.ColCount then
  begin
    for Column := SG.ColCount - 1 downto AtColNumber + 1 do
    begin
      SG.Cols[Column].Assign(SG.Cols[Column - 1]);
      SG.Colwidths[Column] := SG.Colwidths[Column - 1];
    end;

    SG.Cols[AtColNumber].Text := '';
    SG.Colwidths[AtColNumber] := Wdth;
  end;
end;


Solve 3:

type
  TStringGridExSortType = (srtAlpha, srtInteger, srtDouble);

procedure GridSort(SG: TStringGrid; ByColNumber, FromRow, ToRow: integer;
  SortType: TStringGridExSortType = srtAlpha);
var
  Temp: TStringList;

  function SortStr(Line: string): string;
  var
    RetVar: string;
  begin
    case SortType of
      srtAlpha: Retvar := Line;
      srtInteger: Retvar := FormatFloat('000000000', StrToIntDef(trim(Line), 0));
      srtDouble:
        try
          Retvar := FormatFloat('000000000.000000', StrToFloat(trim(Line)));
        except
          RetVar := '0.00';
        end;
    end;

    Result := RetVar;
  end;

  // Recursive QuickSort
  procedure QuickSort(Lo, Hi: integer; CC: TStrings);

    procedure Sort(l, r: integer);
    var
      i, j: integer;
      x: string;
    begin
      i := l;
      j := r;
      x := SortStr(CC[(l + r) div 2]);
      repeat
        while SortStr(CC[i]) < x do
          inc(i);
        while x < SortStr(CC[j]) do
          dec(j);
        if i <= j then
        begin
          Temp.Assign(SG.Rows[j]); // Swap the 2 rows
          SG.Rows[j].Assign(SG.Rows[i]);
          SG.Rows[i].Assign(Temp);
          inc(i);
          dec(j);
        end;
      until i > j;
      if l < j then
        sort(l, j);
      if i < r then
        sort(i, r);
    end;

  begin {quicksort}
    Sort(Lo, Hi);
  end;

begin
  Temp := TStringList.Create;
  QuickSort(FromRow, ToRow, SG.Cols[ByColNumber]);
  Temp.Free;
end;

Nincsenek megjegyzések:

Megjegyzés küldése