AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

StringGrid sortieren

Ein Thema von yankee · begonnen am 4. Mai 2007 · letzter Beitrag vom 31. Jul 2011
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#1

StringGrid sortieren

  Alt 4. Mai 2007, 23:20
Hi @ll,

ich habe Ende 2004 schonmal eine procedure dafür in der CodeLib geposted. Da ich gerade eine Frage dazu bekam bin ich mal wieder auf diese aufmerksam geworden und habe mir überlegt, dass ich das besser kann und nochmal gerne eine schnellere und besser vorschlagen würde:
Delphi-Quellcode:
uses Grids,Classes;
var col: integer;

function CompareStringGridRows(item1,item2: Pointer):integer;
var c1,c2: ^char;
    n1,n2: integer;
begin
  c1 :=@TStrings(item1).Strings[col][1];
  c2 :=@TStrings(item2).Strings[col][1];
  while (c1^ <>#0) and (c2^ <>#0) do
  begin
    if ((c1^ in ['0'..'9']) and (c2^ in ['0'..'9'])) then
    begin
      n1 :=0;
      n2 :=0;
      while (c1^ in ['0'..'9']) do
      begin
        n1 :=n1*10+ord(c1^)-ord('0');
        inc(c1);
      end;
      while (c2^ in ['0'..'9']) do
      begin
        n2 :=n2*10+ord(c2^)-ord('0');
        inc(c2);
      end;
      if n1 > n2 then
      begin
        result :=1;
        exit
      end
      else if n1 < n2 then
      begin
        result :=-1;
        exit;
      end;
    end
    else //at least one is not a number
    begin
      if c1^ > c2^ then
      begin
        result :=1;
        exit;
      end
      else if c1^ < c2^ then
      begin
        result :=-1;
        exit;
      end;
    end;
    inc(c1);
    inc(c2);
  end;
  if c1^ =#0 then
  begin
    if c2^ =#0 then result :=0
    else result :=-1;
  end
  else result :=1;
end;

procedure SortStringGrid(thegrid: TStringGrid; const col: integer);
var rows: TList;
    i: integer;
    tmp: TStrings;
begin
  rows :=TList.Create;
  rows.Capacity :=thegrid.RowCount;
  for i:=0 to thegrid.RowCount -1 do
  begin
    tmp :=TStringList.Create;
    tmp.AddStrings(thegrid.Rows[i]);
    thegrid.Rows[i].Clear;
    rows.Add(tmp);
  end;
  rows.Sort(CompareStringGridRows);
  for i:=0 to thegrid.RowCount -1 do
  begin
    thegrid.Rows[i].Assign(rows[i]);
  end;
  rows.Free;
end;
Die Funktion sortiert nicht nur Spalten mit Zahlen und Zeichen, sondern auch Spalten mit gemischten Werten.
Soweit ich getested habe funktioniert die Funktion auch, hat aber 1 dicken Nachteil:
Sie braucht die globale Variable col für die Vergleichsunktion. Komme ich irgendwie drumrum mir 'ne eigene Sortierfunktion zu schreiben und kann dabei trotzdem eine globale Variable verwenden?
Und was genau macht Assign()? Kann es hierbei zu Speicherlecks führen? Also gibt Assign das alte Objekt frei oder wie soll ich mir das generell vorstellen?
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
BenjaminH

Registriert seit: 14. Okt 2004
Ort: Freiburg im Breisgau
713 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: StringGrid sortieren

  Alt 6. Jul 2007, 16:51
Ich hab die Sortierfunktion jetzt bei mir auch im Einsatz. Aber um etwas ergänzt, damit sie auch diese Einträge sortieren kann:
Code:
9d
9a
9c
9b
Nach
Delphi-Quellcode:
if n1 > n2 then
begin
  result :=1;
  exit
end
else if n1 < n2 then
begin
  result :=-1;
  exit;
end
hab ich noch das eingefügt:
Delphi-Quellcode:
else
begin
  Dec(c1);
  Dec(c2);
end;
Benjamin
  Mit Zitat antworten Zitat
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#3

Re: StringGrid sortieren

  Alt 7. Jul 2007, 10:55
@BenjaminH:
Ich habe zwar lange gebraucht, bis ich das Problem verstanden habe, aber ich glaube jetzt ist es mir klar. Nur ist deine Lösung so nicht "richtig"...

Es wäre besser/schöner das inc(c1)/inc(c2) in Zeile 50 noch in den direkt darüber liegenden else-Block zu verschieben.

*meinen Post oben editier*

EDIT: toll... mit Editieren ist Pustekuchen.
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
Benutzerbild von _frank_
_frank_

Registriert seit: 21. Feb 2003
Ort: Plauen / Bamberg
922 Beiträge
 
Delphi 3 Professional
 
#4

Re: StringGrid sortieren

  Alt 7. Jul 2007, 13:53
hat das evtl. schon jemand mit sortierrichtungen implementiert?

ich hab das mal versucht, leider funktioniert das nicht so wirklich...wird trotzdem normal (aufsteigend) sortiert. der Debugger sagt mir in der Sortier-Procedure immer result ist 0 , obwohl ja offensichtlich sortiert wird...

ich hab mal das komplette test-programm angehängt...

Gruß Frank
Angehängte Dateien
Dateityp: zip stringgridsort_982.zip (133,5 KB, 28x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#5

Re: StringGrid sortieren

  Alt 7. Jul 2007, 14:38
Jetzt nochmal die CompareFunktion mit Sortierrichtung:
Delphi-Quellcode:
var col,dir: integer; //aufsteigend: dir=1, absteigend: dir=-1
function CompareStringGridRows(item1,item2: Pointer):integer;
var c1,c2: ^char;
    n1,n2: integer;
begin
  c1 :=@TStrings(item1).Strings[col][1];
  c2 :=@TStrings(item2).Strings[col][1];
  while (c1^ <>#0) and (c2^ <>#0) do
  begin
    if ((c1^ in ['0'..'9']) and (c2^ in ['0'..'9'])) then
    begin
      n1 :=0;
      n2 :=0;
      while (c1^ in ['0'..'9']) do
      begin
        n1 :=n1*10+ord(c1^)-ord('0');
        inc(c1);
      end;
      while (c2^ in ['0'..'9']) do
      begin
        n2 :=n2*10+ord(c2^)-ord('0');
        inc(c2);
      end;
      if n1 > n2 then
      begin
        result :=dir;
        exit
      end
      else if n1 < n2 then
      begin
        result :=dir*-1;
        exit;
      end;
    end
    else //at least one is not a number
    begin
      if c1^ > c2^ then
      begin
        result :=dir;
        exit;
      end
      else if c1^ < c2^ then
      begin
        result :=dir*-1;
        exit;
      end;
      inc(c1);
      inc(c2);
    end;
  end;
  if c1^ =#0 then
  begin
    if c2^ =#0 then result :=0
    else result :=dir*-1;
  end
  else result :=dir;
end;
Das blöde ist: wieder eine globale Variable mehr

EDIT: Position von dem inc(c1)/c2 korrigiert
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
Benutzerbild von _frank_
_frank_

Registriert seit: 21. Feb 2003
Ort: Plauen / Bamberg
922 Beiträge
 
Delphi 3 Professional
 
#6

Re: StringGrid sortieren

  Alt 8. Jul 2007, 00:43
danke yankee,
hab das ganze mal noch um evtl. angehängten Objekte erweitert und das Speicherleck entfernt (temporäre Stringlisten werden erzeugt aber nicht freigegeben).
sollte zumindest eins sein, habs jetzt nicht mit fastmm probiert, aber es kommt keine Exception beim free...

Delphi-Quellcode:
procedure SortStringGrid(thegrid: TStringGrid; const col: integer);
var rows: TList;
    i,j: integer;
    tmp: TStrings;
begin
  rows :=TList.Create;
  rows.Capacity :=thegrid.RowCount-thegrid.fixedrows;
  for i:=theGrid.fixedrows to thegrid.RowCount -1 do
  begin
    tmp :=TStringList.Create;
    for j:=0 to thegrid.ColCount-1 do
      tmp.AddObject(thegrid.cells[j,i],thegrid.Objects[j,i]);
    //tmp.AddStrings(thegrid.Rows[i]);
    thegrid.Rows[i].Clear;
    rows.Add(tmp);
  end;
  rows.Sort(CompareStringGridRows);
  for i:=thegrid.fixedrows to thegrid.RowCount -1 do
  begin
    //thegrid.Rows[i].Assign(rows[i-thegrid.fixedrows]);
    for j:=0 to thegrid.ColCount-1 do
    begin
      thegrid.Cells[j,i]:=TStringlist(rows[i-thegrid.fixedrows]).Strings[j];
      thegrid.Objects[j,i]:=TStringlist(rows[i-thegrid.fixedrows]).Objects[j];
    end;
    TStringlist(rows[i-thegrid.fixedrows]).free;
  end;
  rows.Free;
end;
wenn ich jetzt keinen Schusselfehler gemacht habe, sollte es so hinhauen (kann das mit den Objekten jetzt nicht so auf die Schnelle testen). Teste das spätestens, wenn ichs in den DFM-Editor einbaue
baue mir erstmal noch eine Routine, um einen Pfeil auf die entsprechende Spalte zu malen...

//edit: das komplette Testproggy inkl. Ownerdraw und Pfeil (geht vielleicht noch schöner ) im Anhang für interessierte

Gruß Frank
Angehängte Dateien
Dateityp: zip stringgridsort_135.zip (135,6 KB, 82x aufgerufen)
  Mit Zitat antworten Zitat
Real_Thunder

Registriert seit: 25. Apr 2006
197 Beiträge
 
#7

Re: StringGrid sortieren

  Alt 3. Nov 2007, 08:17
Ich hätte noch eine Frage, und zwar möchte ich das die makierte Zelle vom Stringgrid,
auch nach der Sortierung makiert bleibt. (an anderer stelle).

Ist es irgendwie möglich ? oder geht es nur mit nem eindeutigem identifer... quasi eine zelle mit breite -1 in demr man dan die anfangsreinfolge speichert, und nach dem sortiervorgang in dieser spalte den "identifer" sucht.

ich stelle mir diese art der lösung sehr schmutzig und langsam vor.....

Wenn jemand eine elegantere lösung hat, bitte melden.


MfG Real Thunder
  Mit Zitat antworten Zitat
Benutzerbild von yankee
yankee

Registriert seit: 10. Mär 2004
1.134 Beiträge
 
Lazarus
 
#8

Re: StringGrid sortieren

  Alt 3. Nov 2007, 10:33
Zitat von Real_Thunder:
Ich hätte noch eine Frage, und zwar möchte ich das die makierte Zelle vom Stringgrid,
auch nach der Sortierung makiert bleibt. (an anderer stelle).

Ist es irgendwie möglich ?
In der SortStringGrid-Funktion könntest du beim einfügen der Pointer in die TList den Pointer speichern, der auf deine markierte Zeile passt. Und dann noch in einem int einfach die wievielte Spalte markiert war (das ändert sich ja nicht).
Nach dem Sortieren musst du dann nurnoch den Pointer in der TList wiederfinden (TList hat dafür glaube ich sogar eine fertige Methode) und schon hast du auch die neue Zeile deiner markierten Zelle.
Letzter Tipp: Drogen. Machen zwar nicht glücklich, geben einem aber wenigstens das Gefühl glücklich zu sein.

Have a lot of fun!
  Mit Zitat antworten Zitat
NetSonic

Registriert seit: 10. Mai 2007
124 Beiträge
 
Delphi 10 Seattle Professional
 
#9

Re: StringGrid sortieren

  Alt 5. Nov 2008, 15:14
Ich muss diesen - doch schön älteren Thread - mal eben wieder ausgraben.

Möchte meine StringGrid mit dieser Funktion sortieren, das klappt auch ohne Probleme bei Integer-Werten etc.. Allerdings enthalten die zu sortieren Spalten ein Datum als String im Format TT.MM.JJJJ und dies möchte ich korrekt sortieren. Leider bekomme ich nicht den richtigen Dreh, die Funktion so umzuschreiben, dass das auch wirklich funktioniert. Hat da jemand einen Denkanstoss für mich oder sowas schon gemacht und kann mir da helfen?

Delphi-Quellcode:
var col,dir: integer;

function CompareStringGridRows(item1,item2: Pointer):integer;
var c1,c2: ^char;
    n1,n2: integer;
begin
  c1 :=@TStrings(item1).Strings[col][1];
  c2 :=@TStrings(item2).Strings[col][1];
  while (c1^ <>#0) and (c2^ <>#0) do
  begin
    if ((c1^ in ['0'..'9']) and (c2^ in ['0'..'9'])) then
    begin
      n1 :=0;
      n2 :=0;
      while (c1^ in ['0'..'9']) do
      begin
        n1 :=n1*10+ord(c1^)-ord('0');
        inc(c1);
      end;
      while (c2^ in ['0'..'9']) do
      begin
        n2 :=n2*10+ord(c2^)-ord('0');
        inc(c2);
      end;
      if n1 > n2 then
      begin
        result :=dir;
        exit
      end
      else if n1 < n2 then
      begin
        result :=dir*-1;
        exit;
      end;
    end
    else //at least one is not a number
    begin
      if c1^ > c2^ then
      begin
        result :=dir;
        exit;
      end
      else if c1^ < c2^ then
      begin
        result :=dir*-1;
        exit;
      end;
      inc(c1);
      inc(c2);
    end;
  end;
  if c1^ =#0 then
  begin
    if c2^ =#0 then result :=0
    else result :=dir*-1;
  end
  else result :=dir;
end;

procedure SortStringGrid(thegrid: TStringGrid; const col: integer);
var rows: TList;
    i,j: integer;
    tmp: TStrings;
begin
  rows :=TList.Create;
  rows.Capacity :=thegrid.RowCount-thegrid.fixedrows;
  for i:=theGrid.fixedrows to thegrid.RowCount -1 do
  begin
    tmp :=TStringList.Create;
    for j:=0 to thegrid.ColCount-1 do
      tmp.AddObject(thegrid.cells[j,i],thegrid.Objects[j,i]);
    //tmp.AddStrings(thegrid.Rows[i]);
    thegrid.Rows[i].Clear;
    rows.Add(tmp);
  end;
  rows.Sort(CompareStringGridRows);
  for i:=thegrid.fixedrows to thegrid.RowCount -1 do
  begin
    //thegrid.Rows[i].Assign(rows[i-thegrid.fixedrows]);
    for j:=0 to thegrid.ColCount-1 do
    begin
      thegrid.Cells[j,i]:=TStringlist(rows[i-thegrid.fixedrows]).Strings[j];
      thegrid.Objects[j,i]:=TStringlist(rows[i-thegrid.fixedrows]).Objects[j];
    end;
    TStringlist(rows[i-thegrid.fixedrows]).free;
  end;
  rows.Free;
end;
Gruß, NetSonic
  Mit Zitat antworten Zitat
taaktaak

Registriert seit: 25. Okt 2007
Ort: Radbruch
1.993 Beiträge
 
Delphi 7 Professional
 
#10

Re: StringGrid sortieren

  Alt 5. Nov 2008, 15:26
Mein Rat:

Wenn's auch bei einigen tausend Daten noch schnell sein soll: Vergiss es!

Der Ansatz ist so weit verbreitet wie falsch! Halte die Daten in einer separaten Liste (z.B. TList) und nutze das Grid nur zur Anzeige. Alles andere ist nur für ein paar hundert Daten gut...

// edit1 - Hierzu eine (überzeugende?!) Testanwendung

// edit2 - Du musst eine spezielle Vergleichsprozedur CompareStringGridRows() schreiben, die zwei Zeilen unter Berücksichtigung des Datums vergleicht, d.h. Reihenfolge von tag.monat.jahr umdrehen...
Ralph
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:28 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz