![]() |
ListView bzw. StringList sortieren...
Hi!
Dann werde ich mal austesten, ob ich hier geholfen bekomme :) Also, ich verwende folgenden Code in meinem Programm, mit dem ich eine ListView nach angeklickter Column sortiere (stört euch nicht an der Komponente SmartListView - ist eine einfache ListView Komponente, nur kann man damit schnell und einfach die Inhalte speichern):
Code:
Dann baue ich bei OnColumnClick folgenden Code ein, mit dem ich festlege, welche Column welche Art von Sortierung besitzen soll:
function CustomSortProc(Item1, Item2: TListItem; SortColumn: Integer): Integer; stdcall;
var s1, s2: string; i1, i2: Integer; r1, r2: Boolean; d1, d2: TDateTime; { Helper functions } function IsValidNumber(AString : string; var AInteger : Integer): Boolean; var Code: Integer; begin Val(AString, AInteger, Code); Result := (Code = 0); end; function IsValidDate(AString : string; var ADateTime : TDateTime): Boolean; begin Result := True; try ADateTime := StrToDateTime(AString); except ADateTime := 0; Result := False; end; end; function CompareDates(dt1, dt2: TDateTime): Integer; begin if (dt1 > dt2) then Result := 1 else if (dt1 = dt2) then Result := 0 else Result := -1; end; function CompareNumeric(AInt1, AInt2: Integer): Integer; begin if AInt1 > AInt2 then Result := 1 else if AInt1 = AInt2 then Result := 0 else Result := -1; end; begin Result := 0; if (Item1 = nil) or (Item2 = nil) then Exit; case SortColumn of -1 : { Compare Captions } begin s1 := Item1.Caption; s2 := Item2.Caption; end; else { Compare Subitems } begin s1 := ''; s2 := ''; { Check Range } if (SortColumn < Item1.SubItems.Count) then s1 := Item1.SubItems[SortColumn]; if (SortColumn < Item2.SubItems.Count) then s2 := Item2.SubItems[SortColumn] end; end; { Sort styles } case LvSortStyle of cssAlphaNum : Result := lstrcmp(PChar(s1), PChar(s2)); cssNumeric : begin r1 := IsValidNumber(s1, i1); r2 := IsValidNumber(s2, i2); Result := ord(r1 or r2); if Result <> 0 then Result := CompareNumeric(i1, i2); end; cssDateTime : begin r1 := IsValidDate(s1, d1); r2 := IsValidDate(s2, d2); Result := ord(r1 or r2); if Result <> 0 then Result := CompareDates(d1, d2); end; end; { Sort direction } if LvSortOrder[SortColumn + 1] then Result := - Result; end;
Code:
Mein Problem ist nun aber, dass ich parallel zu den Daten in der ListView noch Daten in einer StringList habe. Diese sollen natürlich mitsortiert werden, sonst werden die Daten ja durcheinander gewirbelt.
procedure TForm1.SmartListView1ColumnClick(Sender: TObject;
Column: TListColumn); begin if Column.Index = 1 then LvSortStyle := cssAlphaNum; if Column.Index = 2 then LvSortStyle := cssDateTime; if Column.Index = 3 then LvSortStyle := cssDateTime; if Column.Index = 4 then LvSortStyle := cssAlphaNum; if Column.Index = 5 then LvSortStyle := cssAlphaNum; SmartListView1.CustomSort(@CustomSortProc, Column.Index -1); end; Folgenden Code habe ich schon getestet, funktioniert aber nicht:
Code:
Ich bekomme dann einen Ausnahmefehler.
TerminList : TStringList;
begin TerminList.CustomSort(@CustomSortProc); end; Wäre echt nett, wenn mir jemand sagen könnte, worin mein Problem besteht. Gruß Yheeky |
Hallo Yheeky,
eine Antwort habe ich auch nicht, aber das:
Code:
Könnte man eleganter mit case lösen.
procedure TForm1.SmartListView1ColumnClick(Sender: TObject;
Column: TListColumn); begin if Column.Index = 1 then LvSortStyle := cssAlphaNum; if Column.Index = 2 then LvSortStyle := cssDateTime; if Column.Index = 3 then LvSortStyle := cssDateTime; if Column.Index = 4 then LvSortStyle := cssAlphaNum; if Column.Index = 5 then LvSortStyle := cssAlphaNum; SmartListView1.CustomSort(@CustomSortProc, Column.Index -1); end; |
Hi,
ich finde dein Text doch irgendwo extrem lang. Hier ist mal meiner.
Code:
Aufrufen dann damit:
procedure TForm1.ListViewsColumnClick(Sender: TObject;
Column: TListColumn); begin ColumnToSort:=Column.Index; (Sender as TCustomListView).AlphaSort; //ist extra so allgemein geschrieben end; procedure TForm1.ListViewsCompare(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer); var i:integer; begin if ColumnToSort = 0 then Compare:=CompareText(Item1.Caption,Item2.Caption) else begin i:=ColumnToSort -1; Compare:=CompareText(Item1.SubItems[i],Item2.SubItems[i]); end; end;
Code:
Statt dem Button1Click, kannst du eben auch dein ColumnClick nehmen
procedure TForm1.Button1Click(Sender: TObject);
begin ColumnToSort:=0; //Hier wird die Spalte angegeben, nachder Sortiert werden soll; 0 wäre also die erste/Caption ListViewKKLok.AlphaSort; end; Grüsse, Daniel :) |
@Daniel B:
Was Yheeky's Code so lang macht, ist wohl, dass er vorher noch verschiedene Dinge prüft usw., aber so genau habe ich mir seinen Code auch nicht angesehen, da das Sortieren des Lsutviews ja geht. Sein Problem ist, er hat auch noch ein Stringgrid, welches mit sortiert werden soll. |
Re: ListView bzw. StringList sortieren...
Zitat:
Vielleicht nicht die beste/schönste Lösung, aber auf jedenfall eine die gehen würde. :) Grüsse, Daniel :) |
Zitat:
Grüsse, Daniel :) |
Ups :oops:.
|
Das werde ich dir jetzt aber sehr übel nehmen. :twisted:
Grüsse, Daniel :) |
Moin Yheeky,
ich denke mal, dass Dein Problem nur darin besteht, dass Du für einen ListView und eine StringList nicht die gleiche CustomSortProc benutzen kannst. Für die StringList müsstest Du Dir halt eine angepasste Sortierroutine erstellen. Im Prinzip ähnelt eine CustomSortProc einer Callback Funktion. Hier ist der Name auch nur Platzhalter für die Prozedur/Funktion, die man erstellt. Die CustomSortProc kann also heissen wie auch immer man will, solange der Aufbau (Parameter, Rückgabewert) der Vorgabe entspricht. |
Zuerst mal Danke für die schnellen Antworten:
@Christian Seehase: Zitat:
@Daniel B. Zitat:
Gruß Yheeky |
Moin Yheeky,
Du hast Dir doch schon eine CustomSortProc für den Listview gebaut. Nenn die doch, z.B. SortProcListView. Nun erstellst Du Dir noch eine für die StringList und nennst die dann SortProcStringList. Wie gesagt, der Name der Prozedure spielt keine Rolle, solange der Aufbau der Funktion stimmt. Oder hab' ich da jetzt Dein Problem missverstanden? |
Moin Chrischi :wink:
Die Procedure habe ich mir aus dem FAQ vom SwissDelphiCenter "geklaut" :D Klar könnte ich mir eine andere Funktion bauen, will nur fragen, ob vielleicht jemand schon den passenden Code für mich parat hat. Gruß Yheeky |
Moin Yheeky,
da hätte ich noch eine Idee. Ich gehe dazu mal davon aus, dass es zu jedem ListView Item auch genau einen korrespondierenden String in der StringList gibt. Du könntest, da Du ja mehrere Spalten hast, dem jeweils ersten SubItem ein Object anhängen, und zwar den korrespondierenden String. Dann würden die StringList zwar nicht sortiert werden, aber der Zusammenhalt zwischen den Zeilen im ListView und der StringList wäre gewährleistet:
Code:
ABER:
// Anhängen des Strings
ListView1.Items.Add; ListView1.Items[ListView1.Items.Count-1].SubItems.AddObject('TEXT',TObject(slMyStringList[0])); // Auslesen des Strings sStringVariable := String(ListView1.Items[ListView1.Items.Count-1].SubItems.Objects[0]);
|
Danke Christian!
Ich werde es morgen mal testen und dir dann bescheid geben. Gruß Yheeky |
Also in einer ListView passiert bei mir auch irgendwie nichts :cry:
Hat noch jemand eine Idee? Gruß Yheeky |
Ich habe gerade eben die Idee bekommen, wie ich dem ein oder anderen mein Problem ein wenig näherbringen kann. Also, ich möchte genau das machen, was ich mit Outlook Express machen kann. Ich kann die Mails nach Datum, Betreff, Empfänger,... ordnen. Ich kann außerdem jedem Eintrag den Status "Gelesen" bzw. "Ungelesen" zuweisen. Ein nicht gelesener Beitrag wird fett markiert - macht sich also dadurch bemerkbar. Genau das möchte ich auch machen...bei Outlook Express ist das ja auch so, dass der Status erhalten bleibt, auch wenn ich die ListView sortiere...dann muss das doch irgendwie funktionieren :?
Ich hoffe, mir kann jetzt noch jemand helfen! Gruß Yheeky |
Zitat:
wie man dieses Problem mit dem Listview lösen kann, weiss ich in Moment leider auch nicht. Nur ich wollte sagen, dass ich vor paar Wochen auf Torry glaube ich Kompos gesehen habe, die das Aussehen wie beim Outlook bringen kann. Denke aber dass Du wohl trotzdem ListView verwenden willst. Ich kann ja nochmal nach der Kompo suchen wenn DU möchtest. |
Du kannst zusätzlich zu den "normalen" Infos auch Objekte speichern. Das klappt bei Listboxen, Comboboxen und natürlich auch bei ListViews. Ein Beispiel habe ich gerade nicht parat, aber das läuft dann auf´s Typecasting hinaus, bei dem du die einzelnen Eigenschaften eines Objektes abfragen und dann z.B. in der Liste anzeigen lassen kannst.
(Also ein Beispiel hätte ich schon, aber wäre für einen TreeView. Das Prinzip ist zwar das selbe, aber ich will keine Verwirrung stiften. Noch nicht.) Lange Rede, kurzer Sinn: neben den üblichen Dingen kannst du in diesen Eigenschaften auch ein "Gelesen"-Flag unterbringen, über das du die Anzeige in der Liste regelst. Das sollte dann auch unabhängig von der Sortierung sein, so dass die Ausgabe deinem gewünschten Ergebnis entspricht. |
Moin Mathias,
wirf doch bitte mal einen Blick auf mein Beispiel zum Anhängen von Objecten an ListView Items weiter oben in diesem Thread. Eventuell habe ich da ja einen Fehler eingebaut, denn laut Yheeky, geht's bei ihm so nicht. :? Mit ListView.Items hab' ich das noch nicht gemacht. Beim TreeView klappt's bei mir hingegen allerbest. @All Wo wir gerade das Thema Objekte an Items von StringListen anhängen haben: Mit RichEdit.Lines und Memo.Lines geht's nicht. |
Hi @all...
habe den Code gerade nochmal ausgetestet und ich muss zu meiner Schmach sagen, dass der Code einwandfrei funzt :lol: Da muss mir wohl beim ersten Mal ein Fehler unterlaufen 8) ...Sorry. Danke an alle! Gruß Yheeky |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:37 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz