Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Probleme beim Sortieren von ListView
Stefan S. - Mo 02.04.07 11:27
Titel: Probleme beim Sortieren von ListView
Hallo allerseits.
Ich verwende eine ListView-Komponente zum Anzeigen der Daten von Personen in einer Tabelle (mit ViewStyle = vsReport). Diese Daten können auch nach den einzelnen Kategorien sortiert werden, indem man auf die Spalten-Header klickt (wenn man ein zweites Mal klickt, werden die Daten umgekehrt geordnet, wie auch im Windows-Explorer). Dabei kommt es aber zu zweierlei Problemen:
Zum einen tue ich mich schwer, bei einem Klick auf einen Tabelleneintrag darauf zu schließen, um welchen Eintrag es sich handelt. Denn "Selected.Index" richtet sich ja nach der Position des Eintrags in der Tabelle und das bringt mir nichts, weil durch das Sortieren theoretisch jeder Eintrag an jeder Position sein kann. Natürlich habe ich die Caption des jeweils ausgewählten Eintrages und könnte dann in dem Array, in dem die Daten gespeichert sind, nach der Person suchen, die diesen Namen hat, allerdings finde ich das sehr unschön, weil schließlich auch zwei Personen den selben Namen haben könnten (selbst wenn das in der Praxis praktisch nicht vorkommen sollte). Woher also kann ich wissen, um welchen Eintrag es sich bei dem ausgewählten handelt? Geht das vielleicht mit der "Data"-Eigenschaft der einzelnen Items, die auf eine Datenstruktur zeigen kann (die dann vielleicht die Kennnummern der Einträge enthält)?
Ein weiteres Problem habe ich beim Sortieren. Das normale Sortieren (beim ersten Klick auf einen Spalten-Header) funktioniert ohne Probleme, aber das umgekehrte Sortieren (beim zweiten Klick) nur zum Teil. Um das umzusetzen hab ich hier im Forum mal ein bisschen rumgesucht und bin fündig geworden, warum der Code bei mir nicht hunderprozentig funktioniert, ist mir jetzt aber nicht klar.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
| var Sortier_Spalte: Integer;
procedure TfoMain.lvSpielerlisteCompare(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer); var i: Integer; Wert1, Wert2: String; begin If Sortier_Spalte = 0 then Compare := CompareText(Item1.Caption,Item2.Caption) Else begin i := Sortier_Spalte - 1; If lvSpielerliste.Columns[i+1].Tag >= 1 then begin Wert1 := Item1.SubItems[i]; Wert2 := Item2.SubItems[i]; try Compare := StrToInt(Wert1) - StrToInt(Wert2); except Compare := 0; end; end Else Compare := CompareText(Item1.SubItems[i],Item2.SubItems[i]); end; If Sortierung_Invers = True then Compare := not Compare; end;
procedure TfoMain.lvSpielerlisteColumnClick(Sender: TObject; Column: TListColumn); begin If Sortier_Spalte <> column.Index then Sortierung_Invers := False Else Sortierung_Invers := not Sortierung_Invers; Sortier_Spalte := Column.Index; (Sender as TCustomListView).AlphaSort; end; |
Und so funktioniert der Code:
Ich habe zu Testzwecken einige Einträge mit den Nachnamen Ahrens, Becker, Mayer, Müller, Schmidt, Schneider und Werner eingefügt (Caption = Nachname). Beim normalen Sortieren sind sie genau in dieser Reihenfolge, wie es sein soll, wenn man ein zweites Mal auf den Spalten-Header klickt und damit "Sortierung_Invers" = True ist, sieht es jedoch so aus:
Werner, Schmidt, Schneider, Müller, Mayer, Ahrens, Becker
Wie man sieht ist das Ergebnis im großen und ganzen richtig, nur sind der 2. und 3. Wert sowie der vorletzte und letzte komischerweise vertauscht. Findet jemand den Fehler?
Keldorn - Mo 02.04.07 19:37
Hallo
bei Müller steht ein ü, damit kommt comparetext nicht klar und du erhälst falsche Ergebnisse.
Verwende stattdessen ansicompartext, dann gehts.
Bei Delphi 6 ging dann nicht mehr compare:=not compare, mit compare:=(-1)* compare funktionierts aber dann.
Mfg Frank
Stefan S. - Di 03.04.07 11:34
Wunderbar, es funktioniert perfekt. :) Dankeschön.
Kann mir bei dem ersten Problem auch noch jemand helfen? Wie finde ich bei einer beliebig sortierten Liste raus, um welches Element es sich bei dem aktuell ausgewählten handelt? Kann ich jedem Eintrag neben "Caption" und "Subitems" auch noch irgendwie eine "Kennnummer" verpassen? Oder geht es wirklich nicht anders als dass ich anhand einer der Spalten darauf schließe?
uro3 - Di 03.04.07 11:59
Du kannst jeden Eintrag ein Object zu ordnen.
Wenn du eine Zahl zu ordnen willst geht
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| var Nr : Integer;
begin ........
lvListView1.AddItem('dein text',TObject(Nr)); |
oder du benutzt die Data Eigenschaft vom TListItem
Stefan S. - Mi 04.04.07 09:50
Ich hab es jetzt mal so gemacht:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| with foMain.lvSpielerliste.Items.Add do begin Caption := Spieler[i-1].Name; (...) Data := @Spieler[i-1]; end; |
Spieler ist ein dynamischer Array von TSpieler, ein Record, das u.a. das Feld "Name" (String) enthält.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TfoMain.lvSpielerlisteChange(Sender: TObject; Item: TListItem; Change: TItemChange); var P: ^TSpieler; begin If lvSpielerliste.Selected <> nil then begin P := lvSpielerliste.Selected.Data; laSpieler_Name.Caption := P^.Name; (...) end; end; |
Das ganze funktioniert auch wunderbar, mit einer Einschränkung: Ich habe zwei Checkboxen, mit denen man einstellen kann, dass Einträge mit bestimmten Eigenschaften angezeigt oder eben nicht angezeigt werden sollen. Wenn man jetzt bei einer von beiden das Häkchen entfernt sind folglich weniger Einträge in der Liste, insgesamt auch weniger, als der dynamische Array "Spieler" lang ist. Nun kommt es an der Stelle, an der ich auf P^.Name zugreife, zu einer Zugriffsverletzung, egal auf welchen Eintrag ich klicke. Man könnte vermuten, dass P auf ein Spieler[i] zeigt, das nicht existiert, kann aber eigentlich nicht sein, weil "Selected" ja immer der ausgewählte Eintrag ist und "Data" dabei stets auf die selbe Stelle zeigt, egal ob jetzt 7 Einträge in der Liste sind wie am Anfang oder 2 (Häkchen vor Checkbox 1 weg) bzw. 5 (Checkbox 2). Wie kann es also zu der Zugriffsverletzung kommen?
EDIT: Hab das Problem gefunden: War mal wieder etwas ganz dummes, nämlich hab ich einfach an einer anderen Stelle die Zuweisung von "Data" vergessen. Damit wäre dann alles geklärt.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!