// Getestet mit D4 unter XP

// Ein Stringgrid wird anhand einer (oder mehrerer) bestimmten Spalte(n)
// zeilenweise sortiert, wobei eine Start- und eine Endzeile festgelegt
// werden kann, um nur einen vorgegebenen Bereich zu sortieren. Mit der
// Variablen "
aufsteigend" legt man die Sortierreihenfolge fest. Die Variable
// "
fix" bestimmt, ob feste Spalten (FixedCols) auch mit sortiert werden.
// Bitte beachten: Die Zählung der Zeilen und Spalten beginnt bei Null.


// 1. Einfache Variante
//   Die Prozedur ist gedacht um Wörter in den Zellen des Grids alphabetisch
//   zu sortieren, nicht aber Zahlen. Da von links nach rechts geprüft wird,
//   wäre
80 größer als 10000, denn 8 ist größer als 1.
 

procedure SortGrid(Grd: TStringGrid; Spalten: array of Word; BeginnZeile, 
  Endzeile: Integer; aufsteigend, fix: boolean); 
var i, j, k, h, a: integer; 
  function verglsp(s: integer): integer; 
  begin 
    result := ansistrIcomp(pchar(grd.cells[s, j]), 
      pchar(grd.cells[s, j + k])); 
  end; 
  function vergl: boolean; 
  var x, w: integer; 
    procedure v_erg; 
    begin 
      x := verglsp(Spalten[w]); 
    end; 
  begin 
    w := 0; 
    v_erg; 
    while w < h do begin 
      inc(w); 
      if x = 0 then v_erg; 
    end; 
    case aufsteigend of 
      true: result := x > 0; 
    else result := x < 0; 
    end; 
  end; 
  procedure doit; 
  var y: integer; 
    s: string; 
  begin 
    for y := a to grd.colcount - 1 do begin 
      s := grd.cells[y, j]; 
      grd.cells[y, j] := grd.cells[y, j + k]; 
      grd.cells[y, j + k] := s; 
    end; 
  end; 
begin 
  with grd do begin 
    a := ord(not fix) * fixedcols; 
    editormode := false; 
    h := High(Spalten); 
    k := EndZeile shr 1; 
    while k > 0 do begin 
      for i := BeginnZeile to EndZeile - k do begin 
        j := i; 
        while (j >= BeginnZeile) and vergl do begin 
          doit; 
          if j > k then dec(j, k) else j := BeginnZeile; 
        end; 
      end; 
      k := k shr 1; 
    end; 
  end; 
end; 
 
 
// Beispielaufruf: 
// Die Sortierung erfolgt zunächst nach Spalte 1 (z.B. Familiennamen), 
// und dann noch nach Spalte 2 (z.B. Vornamen). 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
  SortGrid(Stringgrid1, [1, 2], Stringgrid1.FixedRows, 
    Stringgrid1.RowCount - 1, true, false); 
end;

// -----------------------------------------------------------------------


// 2. Erweiterte Variante
// Die Variante 1 wurde erweitert, um auch eine Zahlenfolge oder ein Datum
// sortieren zu können. Mittels des Arrays "
Art" wird der Funktion mitgeteilt,
// wie jeder Spalte zu sortieren ist. Sollte man jedoch versuchen, eine
// Spalte, welche Text enthält, als Zahlen zu sortieren, so kommt es
// logischerweise zu einer Fehlermeldung. Im umgekehrten Fall kann man
// natürlich Zahlen sortieren, als wären sie Strings.
// Mit der Variablen "
LeerZuletzt" wird festgelegt, ob Leerzeilen nach unten
// oder nach oben sortiert werden. Allerdings gibt es hier einen Sonderfall.
// Bei Zahlenkolonnen soll manchmal eine leere Zelle als "0" gewertet werden.
// Das kann man über die Variable "
Leer" einstellen. Diese wird aber nur beachtet,
// wenn eine Spalte nach Zahlen sortiert werden soll.
// Mittels "
SpaltenAngabenAnpassen" legt man fest, was passiert, wenn ein Wert
// im Array "
Spalten" zu klein ist, oder größer als ColCount - 1. Entweder wird
// der Wert passend gemacht, oder es erscheint eine Fehlermeldung.

type 
  SortType = (Num, Dat, Txt, Unknow);  // Zahl,  Datum/Zeit,  Text,  unbekannt 
  LeerType = (wieNull, wieLeer); 
 
procedure SortGrid(Grd: TStringGrid; Spalten: array of Word; 
  Art: array of SortType; BeginnZeile, Endzeile: Integer; 
  aufsteigend, fix, SpaltenAngabenAnpassen, LeerZuletzt: boolean; 
  Leer: Leertype); 
var 
  i, j, k, h, a: integer; 
  dm: TDateTime; 
  em: extended; 
  tm: string; 
  function verglsp(s, o: integer): integer; 
  var 
    d1, d2: TDateTime; 
    e1, e2: extended; 
    s1, s2: string; 
  begin 
    case Art[o] of 
      Num: begin 
          try 
            if grd.cells[s, j] = '' then e1 := em else 
              e1 := strtofloat(stringreplace(grd.cells[s, j], 
                '.', '', [rfreplaceall])); 
            if grd.cells[s, j + k] = '' then e2 := em else 
              e2 := strtofloat(stringreplace(grd.cells[s, j + k], 
                '.', '', [rfreplaceall])); 
          except 
            raise exception.create('Werte entsprechen nicht dem Typ Zahl'); 
          end; 
          result := ord(e1 = e2) + ord(e1 > e2) shl 1 - 1; 
        end; 
      Dat: begin 
          try 
            if grd.cells[s, j] = '' then d1 := dm else 
              d1 := strtodatetime(grd.cells[s, j]); 
            if grd.cells[s, j + k] = '' then d2 := dm else 
              d2 := strtodatetime(grd.cells[s, j + k]); 
          except 
            raise exception.create('Werte entsprechen nicht dem Typ Datum/Zeit'); 
          end; 
          result := ord(d1 = d2) + ord(d1 > d2) shl 1 - 1; 
        end; 
    else begin 
        if grd.cells[s, j] = '' then s1 := tm else 
          s1 := grd.cells[s, j]; 
        if grd.cells[s, j + k] = '' then s2 := tm else 
          s2 := grd.cells[s, j + k]; 
        result := ansistrIcomp(pchar(s1), pchar(s2)); 
      end; 
    end; 
  end; 
  function vergl: boolean; 
  var 
    x, w: integer; 
    procedure v_erg; 
    begin 
      x := verglsp(Spalten[w], w); 
    end; 
  begin 
    w := 0; 
    v_erg; 
    while w < h do begin 
      inc(w); 
      if x = 0 then v_erg; 
    end; 
    case aufsteigend of 
      true: result := x > 0; 
    else result := x < 0; 
    end; 
  end; 
  procedure doit; 
  var 
    y: integer; 
    s: string; 
  begin 
    for y := a to grd.colcount - 1 do begin 
      s := grd.cells[y, j]; 
      grd.cells[y, j] := grd.cells[y, j + k]; 
      grd.cells[y, j + k] := s; 
    end; 
  end; 
begin 
  if aufsteigend = LeerZuletzt 
    then begin 
    if leer = wieNull then em := 0 else 
      em := 1.1E+4932; 
    dm := strtodatetime('31.12.9999 23:59'); 
    tm := stringofchar('Z', 255); 
  end else begin 
    if leer = wieNull then em := 0 else 
      em := 3.4E-4932; 
    dm := strtodatetime('01.01.0001'); 
    tm := ''; 
  end; 
  with grd do begin 
    if (Endzeile > rowcount - 1) or (Endzeile < BeginnZeile) 
      or (BeginnZeile < 0) then 
      raise exception.create('Falsche Zeilenangabe'); 
    a := ord(not fix) * fixedcols; 
    h := High(Spalten); 
    if h <> High(Art) then 
      raise exception.create('Falsche Anzahl bei Sortiertyp'); 
    if SpaltenAngabenAnpassen then begin 
      for k := 0 to h do 
        if (Spalten[k] > colcount - 1) then Spalten[k] := colcount - 1 
        else if (Spalten[k] < a) then Spalten[k] := a; 
    end else 
      for k := 0 to h do 
        if (Spalten[k] > colcount - 1) 
          or (Spalten[k] < a) then 
          raise exception.create('Falsche Spaltenangabe'); 
    editormode := false; 
    k := EndZeile shr 1; 
    while k > 0 do begin 
      for i := BeginnZeile to EndZeile - k do begin 
        j := i; 
        while (j >= BeginnZeile) and vergl do begin 
          doit; 
          if j > k then dec(j, k) else j := BeginnZeile; 
        end; 
      end; 
      k := k shr 1; 
    end; 
  end; 
end; 
 

 
// -------- Beispielaufrufe -------- 
 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
// --- zum Testen --- 
  with stringgrid1 do begin 
    ColCount := 5; 
    RowCount := 8; 
    FixedCols := 1; 
    FixedRows := 1; 
 
    cells[1, 1] := 'Voigt'; 
    cells[1, 2] := 'Müller'; 
    cells[1, 3] := 'Müller'; 
    cells[1, 4] := 'Müller'; 
    cells[1, 5] := 'Müller'; 
    cells[1, 6] := 'Müller'; 
 
    cells[2, 1] := 'Susanne'; 
    cells[2, 2] := 'Arnold'; 
    cells[2, 3] := 'Xaver'; 
    cells[2, 4] := ''; 
    cells[2, 5] := 'Dieter'; 
    cells[2, 6] := 'Dieter'; 
 
    cells[3, 1] := '30.01.1950'; 
    cells[3, 2] := '30.01.1950'; 
    cells[3, 3] := '10.03.1966'; 
    cells[3, 4] := '10.02.1947'; 
    cells[3, 5] := '19.12.1947'; 
    cells[3, 6] := '19.12.1940'; 
 
    cells[4, 1] := '1.777,1'; 
    cells[4, 2] := '9.978'; 
    cells[4, 3] := ''; 
    cells[4, 4] := '-111,704'; 
    cells[4, 5] := '123'; 
    cells[4, 6] := '0,00'; 
  end; 
end; 
 
 
 
// Es wird nach Name, Vorname und Geburtstag sortiert 
 
procedure TForm1.Button3Click(Sender: TObject); 
begin 
  SortGrid(Stringgrid1, [1, 2, 3], [Txt, Txt, Dat], 
    Stringgrid1.FixedRows, Stringgrid1.RowCount - 1, 
    true, false, false, false, wieLeer); 
end; 
 
 
// -----------------------------------------------------------------------
 
// Beim Klick auf den Spaltenkopf wird die 
// jeweilige (einzelne) Spalte sortiert 
 
const 
  aost: array[0..4] of SortType = // Grid hat 5 Spalten; Spalte 0 = Fixed 
  (Unknow, Txt, Txt, Dat, Num); 
 
procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; 
  Shift: TShiftState; X, Y: Integer); 
var 
  arow, acol: integer; 
begin 
  StringGrid1.MouseToCell(X, Y, acol, arow); 
  if arow = 0 then 
    SortGrid(Stringgrid1, [acol], [aost[acol]], 
      Stringgrid1.FixedRows, Stringgrid1.RowCount - 1, 
      true, true, true, true, wieNull); 
end; 


Zugriffe seit 6.9.2001 auf Delphi-Ecke