Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi ListView bzw. StringList sortieren... (https://www.delphipraxis.net/82-listview-bzw-stringlist-sortieren.html)

Yheeky 10. Jun 2002 17:08


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:
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;
Dann baue ich bei OnColumnClick folgenden Code ein, mit dem ich festlege, welche Column welche Art von Sortierung besitzen soll:

Code:
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;
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.

Folgenden Code habe ich schon getestet, funktioniert aber nicht:

Code:
TerminList : TStringList;
begin
TerminList.CustomSort(@CustomSortProc);
end;
Ich bekomme dann einen Ausnahmefehler.

Wäre echt nett, wenn mir jemand sagen könnte, worin mein Problem besteht.

Gruß Yheeky

Luckie 10. Jun 2002 17:14

Hallo Yheeky,
eine Antwort habe ich auch nicht, aber das:
Code:
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;
Könnte man eleganter mit case lösen.

Daniel B 10. Jun 2002 17:18

Hi,

ich finde dein Text doch irgendwo extrem lang. Hier ist mal meiner.

Code:
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;
Aufrufen dann damit:

Code:
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;
Statt dem Button1Click, kannst du eben auch dein ColumnClick nehmen

Grüsse, Daniel :)

Luckie 10. Jun 2002 17:25

@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.

Daniel B 10. Jun 2002 17:30

Re: ListView bzw. StringList sortieren...
 
Zitat:

Zitat von Yheeky
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.

wäre es vielleicht nicht am einfachsten, nach dem Sortieren der LV die SL zu Löschen und mit dem "neuen" Inhalt der LV zu füllen?
Vielleicht nicht die beste/schönste Lösung, aber auf jedenfall eine die gehen würde. :)

Grüsse, Daniel :)

Daniel B 10. Jun 2002 17:32

Zitat:

Zitat von Luckie
Sein Problem ist, er hat auch noch ein Stringgrid, welches mit sortiert werden soll.

Eine StringList

Grüsse, Daniel :)

Luckie 10. Jun 2002 17:33

Ups :oops:.

Daniel B 10. Jun 2002 17:36

Das werde ich dir jetzt aber sehr übel nehmen. :twisted:

Grüsse, Daniel :)

Christian Seehase 10. Jun 2002 18:37

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.

Yheeky 10. Jun 2002 20:15

Zuerst mal Danke für die schnellen Antworten:

@Christian Seehase:
Zitat:

ich denke mal, dass Dein Problem nur darin besteht, dass Du für einen ListView und eine StringList nicht die gleiche CustomSortProc benutzen kannst.
Genau, deswegen hat mir Delphi auch eine Fehlermeldung ausgespuckt, als ich das versucht habe :lol: . Genau das Problem gilt es zu lösen, aber ich weiss selbst nicht wie :(

@Daniel B.
Zitat:

wäre es vielleicht nicht am einfachsten, nach dem Sortieren der LV die SL zu Löschen und mit dem "neuen" Inhalt der LV zu füllen?
Nein, das geht nicht. Ich kann das nicht machen, da die Daten nicht aus der ListView direkt geholt werden. Sie haben nur Einfluss auf die Gestaltung der ListView...

Gruß Yheeky

Christian Seehase 10. Jun 2002 20:29

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?

Yheeky 10. Jun 2002 20:39

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

Christian Seehase 10. Jun 2002 21:30

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:
  // 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]);
ABER:
  1. Die [0] müsste natürlich jeweils durch den entsprechenden Wert ersetzt werden.
  2. Ich weiss nicht, ob das AddObject bei einem ListView überhaupt funkioniert, denn bei TMemo/TRichEdit ist bei den Lines ist diese Methode zwar auch vorhanden, aber leider nicht "mit Leben" gefüllt, sprich da passiert nichts.

Yheeky 10. Jun 2002 22:13

Danke Christian!

Ich werde es morgen mal testen und dir dann bescheid geben.

Gruß Yheeky

Yheeky 11. Jun 2002 10:52

Also in einer ListView passiert bei mir auch irgendwie nichts :cry:

Hat noch jemand eine Idee?

Gruß Yheeky

Yheeky 12. Jun 2002 17:47

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

Darty 12. Jun 2002 18:31

Zitat:

Zitat von Yheeky
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

Hi Yheeky,

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.

MathiasSimmack 12. Jun 2002 18:42

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.

Christian Seehase 12. Jun 2002 18:50

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.

Yheeky 12. Jun 2002 20:04

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 20:18 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