Stringgrid Zellen sortieren.

Rund um die LCL und andere Komponenten
Antworten
Mathias
Beiträge: 4745
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Stringgrid Zellen sortieren.

Beitrag von Mathias »

Wen ich den Button1 drücke, wird wie erwartet nach der erste Spalte sortiert.
Drücke ich dann Button2 dann wird nach der 2. Spalte sortiert. Aber die erste Spalte kommt durcheinander. Bei jedem drücken von Button2, verändert sich die erste Spalte.
Ich will gerne, das die erste Spalte vorsortiert bleibt, so das es im 'a' 2,2,3,3 ist und nicht 2,3,3,2 oder ähnlich.
OpenOffice macht es richtig.

Kann man dies einstellen ?

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
begin
  StringGrid1.FixedCols := 0;
  StringGrid1.FixedRows := 0;
  StringGrid1.ColCount := 2;
  StringGrid1.RowCount := 12;
  StringGrid1.Cols[0].AddCommaText('4,5,6,1,2,3,4,5,6,1,2,3');
  StringGrid1.Cols[1].AddCommaText('b,b,c,c,a,a,b,b,c,c,a,a');
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  StringGrid1.SortColRow(True, 0, 0, StringGrid1.RowCount - 1);
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  StringGrid1.SortColRow(True, 1, 0, StringGrid1.RowCount - 1);
end;   
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

wennerer
Beiträge: 132
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 19.3 Cinnamon, Lazarus 2.1.0, FPC 3.3.1 ,Lazarus Stable 2.0.6,
CPU-Target: x86_64

Re: Stringgrid Zellen sortieren.

Beitrag von wennerer »

Hallo,
bei mir funktioniert es so:

Code: Alles auswählen

procedure 
TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
 CellCoords:=Grid1.MouseCoord(X,Y);
 if (CellCoords.X = 0) and (CellCoords.Y = 0) then Grid1.SortColRow(true,0);
 if (CellCoords.X = 1) and (CellCoords.Y = 0) then Grid1.SortColRow(true,1);
 if (CellCoords.X = 2) and (CellCoords.Y = 0) then Grid1.SortColRow(true,2);
 if (CellCoords.X = 3) and (CellCoords.Y = 0) then Grid1.SortColRow(true,3);
 if (CellCoords.X = 4) and (CellCoords.Y = 0) then Grid1.SortColRow(true,4);
end;


Vielleicht hilft es weiter.
Gruß
Bernd

wp_xyz
Beiträge: 3223
Registriert: Fr 8. Apr 2011, 09:01

Re: Stringgrid Zellen sortieren.

Beitrag von wp_xyz »

In einem Grid nur eine Spalte, unabhängig von den anderen, zu sortieren, ist aber auch nicht die normale Anwendung. Stell dir vor, in einem Grid stehen Name, Vorname, Wohnort und jemand sortiert nach Wohnort - damit werden die ganzen Zuordnungen zerstört.

Wenn du unbedingt eine Spalte allein sortieren willst, dann kopiere sie in eine StringList, sortiere diese und kopiere dann zurück:

Code: Alles auswählen

procedure TForm1.Button2Click(Sender: TObject);
var
  L: TStringList;
begin
  L := TStringList.Create;
  try
    L.Assign(StringGrid1.Cols[1]);
    L.Sort;
    StringGrid1.Cols[1].Assign(L);
  finally
    L.Free;
  end;
end;

Mathias
Beiträge: 4745
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringgrid Zellen sortieren.

Beitrag von Mathias »

In einem Grid nur eine Spalte, unabhängig von den anderen, zu sortieren, ist aber auch nicht die normale Anwendung.

Du hast mich falsch verstanden.

Es sollte so aussehen:

Code: Alles auswählen

2 a
2 a
3 a
3 a
.....


Und nicht so oder ähnlich:

Code: Alles auswählen

2 a
3 a
2 a
3 a
.....

Ich hoffe du verstehst was ich meine ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 3223
Registriert: Fr 8. Apr 2011, 09:01

Re: Stringgrid Zellen sortieren.

Beitrag von wp_xyz »

Ist es dann so, dass die beiden Spalten nach einer Spalte sortiert werden sollen, wobei wenn die Zellen gleich sind, die andere Spalte herangezogen werden soll?

Das könnte man mit einer entsprechenden Vergleichsfunktion erreichen:

Code: Alles auswählen

procedure TForm1.StringGrid1CompareCells(Sender: TObject; ACol, ARow, BCol, BRow: Integer; var Result: integer);
begin
  Result := CompareStr(StringGrid1.Cells[ACol, ARow], StringGrid1.Cells[BCol, BRow]);
  if Result = 0 then begin
    if ACol = 0 then
      Result := CompareStr(StringGrid1.Cells[1, ARow], StringGrid1.Cells[1, BRow])
    else
      Result := CompareStr(StringGrid1.Cells[0, ARow], StringGrid1.Cells[0, BRow])
  end;
end

Mathias
Beiträge: 4745
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringgrid Zellen sortieren.

Beitrag von Mathias »

Ich weis nicht genau was da passiert, aber es scheint zu funktionieren. :)
Den Button1 muss man dabei gar nicht mehr drücken.

Danke

Nachtrag;
Jetzt verstehe ich langsam was passiert:

Code: Alles auswählen

const
  s0 = 'a3';
  s1 = 'c6';
begin
  Caption := CompareStr(s0, s1).ToString;


So wie es aussieht, kann man mit CompareCells eine eigene Vergleichsroutine schreiben.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 4745
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringgrid Zellen sortieren.

Beitrag von Mathias »

Dieser Code hat mich dank dir schon viel weiter gebracht.

Code: Alles auswählen

procedure TForm1.StringGrid1CompareCells(Sender: TObject;
  ACol, ARow, BCol, BRow: integer; var Result: integer);
begin
  Result := CompareStr(StringGrid1.Cells[ACol, ARow], StringGrid1.Cells[BCol, BRow]);
  if Result = 0 then begin
    Result := CompareStr(StringGrid1.Cells[2, ARow], StringGrid1.Cells[2, BRow]);
    if Result = 0 then begin
      Result := CompareStr(StringGrid1.Cells[0, ARow], StringGrid1.Cells[0, BRow]);
    end;
  end;
end;
 
procedure TForm1.StringGrid1HeaderClick(Sender: TObject; IsColumn: boolean;
  Index: integer);
begin
  StringGrid1.SortColRow(True, Index, 1, StringGrid1.RowCount - 1);
end

Jetzt muss ich nur noch einen Weg finden, wen es um Zahlen sortieren geht. Momentan werden diese als String interpretiert.
Dateianhänge
Bildschirmfoto vom 2020-03-22 15-48-29.png
Bildschirmfoto vom 2020-03-22 15-48-29.png (96.55 KiB) 461 mal betrachtet
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 4745
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringgrid Zellen sortieren.

Beitrag von Mathias »

Ich habe noch eine Frage:

Ich habe folgendes Tutorial angeguckt: https://wiki.freepascal.org/TStringGrid
Dort hat es in der unteren Hälfte StringGrid mit einem Sortierpfeil in der Titelleiste, aber ich kann nirgends erkennen, wie das gemacht wird.

Jemand eine Idee ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 3223
Registriert: Fr 8. Apr 2011, 09:01

Re: Stringgrid Zellen sortieren.

Beitrag von wp_xyz »

Der Sortierpfeil wird über der Spalte angezeigt, deren Nummer in SortColumn eingetragen ist. Wird üblicherweise zusammen mit der Eigenschaft ColumnClickSorts automatisch angewendet. Wenn dieses true gesetzt ist, sortiert ein Click auf einem Spaltenheader die Tabelle nach dieser Spalte und zeigt den Sortierpfeil an. Ein zweiter Klick auf derselben Spalte dreht Sortierrichtung und Pfeilrichtung um (SortOrder). Ein Klick auf einer anderen Spalte schaltet Sortierung und Pfeil auf diese Spalte um. Geht ganz automatisch, man muss nur ColumnClickSorts aktivieren. Und wenn du spezielle Wünsche bzgl Sortierreihenfolge hast, wird die OnCompareCells Routine verwendet.

Mathias
Beiträge: 4745
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringgrid Zellen sortieren.

Beitrag von Mathias »

Ein zweiter Klick auf derselben Spalte dreht Sortierrichtung und Pfeilrichtung um (SortOrder).

Ich habe

Code: Alles auswählen

  StringGrid1.ColumnClickSorts := True;
gesetzt.
Und die procedure "StringGrid1HeaderClick" entfernt.
Er sortiert weiterhin, wie erwartet, wen ich in den Header klicke. Auch erscheint jetzt ein Pfeil, der bei jedem Klicken die Richtung wechselt.
Nur bleibt die Sortierreihenfolge immer gleich.

Wen ich "StringGrid1CompareCells" entferne, dann funktioniert es.

Und wenn du spezielle Wünsche bzgl Sortierreihenfolge hast, wird die OnCompareCells Routine verwendet.

Kann CompareCells irgendwo abfragen, in welche Richtung der Pfeil zeigt ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 3223
Registriert: Fr 8. Apr 2011, 09:01

Re: Stringgrid Zellen sortieren.

Beitrag von wp_xyz »

Hier ist der Quelltext der CustomGrid-Methode DoCompareCells:

Code: Alles auswählen

function TCustomStringGrid.DoCompareCells(Acol, ARow, Bcol, BRow: Integer): Integer;
begin
  if Assigned(OnCompareCells) then
    Result:=inherited DoCompareCells(Acol, ARow, Bcol, BRow)
  else begin
    Result:=UTF8CompareText(Cells[ACol,ARow], Cells[BCol,BRow]);
    if SortOrder=soDescending then
      result:=-result;
  end;
end;

Da siehst du im else-Zweig den Normalfall, wenn keine OnCompareCells-Behandlung vorhanden ist: es wird UTF8CompareText aufgerufen und dann, falls die Sortierreihenfolge auf absteigend steht, das Ergebnis invertiert. Dieses fehlt in dem Fall mit OnCompareCells-Handler.

Also musst du die beiden letzten Zeilen (if Grid.SortOrder = soDescending then Result := -Result) ans Endes deiner OnCompareCells mit aufnehmen.

Mathias
Beiträge: 4745
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringgrid Zellen sortieren.

Beitrag von Mathias »

Danke, das war 's. :wink:

Code: Alles auswählen

  if StringGrid1.SortOrder = soDescending then begin
    Result *= -1;
  end;


Das StringGrid so eine mächtige Komponente ist, hätte ich nie gedacht.

Als ich mit den Grid begonnen habe, habe ich mir schon überlegt, wie ich einen Quiksort einsetze. Ab das erübrigt sich ja jetzt.
Dateianhänge
Bildschirmfoto vom 2020-03-24 17-19-40.png
Bildschirmfoto vom 2020-03-24 17-19-40.png (38.77 KiB) 376 mal betrachtet
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

Antworten