Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - TListView Spalten sortieren per Mausklick: Wie ?


Morduk666 - Mi 07.05.03 05:23
Titel: TListView Spalten sortieren per Mausklick: Wie ?
hoi,

hab hier das forum schon abgesucht aber auch nix passendes gefunden. suche ne Lösung wie ich meine listview sortieren kann per klick auf den spaltenkopf. und zwar am besten auf/absteigend.

wenn da einer ne idee hat bin ich dankbar


Delete - Mi 07.05.03 06:53

Hilfe schon gefunden? da ist sogar ein Beispiel drin. Für den Fall, dass deine Hilfe kaputt ist:
Zitat:
This example shows how to use the OnColumnClick and OnCompare events of a list view to let users sort the columns in a report-style list view by clicking on the column headers. This requires a global variable to keep track of the column that was clicked:


Delphi-Quelltext
1:
var ColumnToSort: Integer;                    


Zitat:
The OnColumnClick event handler sets the global variable to indicate the column to sort and calls AlphaSort:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);

begin
  ColumnToSort := Column.Index;
  (Sender as TCustomListView).AlphaSort;
end;


Zitat:
The OnCompare event handler causes the list view to sort on the selected column:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer);
var
  ix: Integer;
begin
  if ColumnToSort = 0 then
    Compare := CompareText(Item1.Caption,Item2.Caption)
  else begin
   ix := ColumnToSort - 1;
   Compare := CompareText(Item1.SubItems[ix],Item2.SubItems[ix]);
  end;

end;


Zitat:
Note: This OnCompare event handler uses the global CompareText function. An application may want to use AnsiCompareText, CompareStr, or AnsiCompareStr instead, depending on whether the comparison should be case-sensitive and whether the locale should be considered.

Aich wenn das aus der Hilfe für den VCL-Listview ist, sollte es genauso beim CLX-Listview gehen.

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Morduk666 - Mi 07.05.03 14:34

hmm. danke ersma. der code funzt recht gut. leider kann man nur in eine richtung sortieren. geht das auch dass er bei nem klick auf/absteigend sortiert ? also sortierreichenfolge umdreht?

vor allem hab ich ein prob mit der sortierung bei zahlenwerten. er sortiert mir z.b. in der reihenfolge: 3, 4, 500, 6, 7, 83, ... statt 3, 4, 6, 7, 83, 500 :((


was issn da zu machen ?freue mich über jede antwort


Keldorn - Mi 07.05.03 14:49

Hallo

onlinehilfe hat folgendes geschrieben:
Die Ereignisbehandlungsroutine für OnCompare vergleicht zwei Listenelemente, die in den Parametern Item1 und Item2 übergeben werden. Weisen Sie dem Parameter Compare 0 zu, wenn Item1 und Item2 in der Sortierreihenfolge gleichrangig sind. Weisen Sie ihm einen Wert unter 0 zu, wenn Item1 kleiner als Item2 ist, und einen Wert über 0, wenn Item1 größer als Item2 ist.

nimm eine weitere Variable columnclicks. Prüfe bei oncolumclick, ob du die gleiche Spalte geklickt hast, wenn ja ändere Columnslicks, wenn nicht setzt die Variable wieder zurück.

bei oncompare prüfst du dann columsclicks, und sortierst entsprechend.
um eine andere sortierreihenfolge zu erhalten, negier den Wert compare

in etwa so (nich großartig getestet)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
var ix: Integer;
begin
  if ColumnToSort = 0 then
    Compare := not (CompareText(Item1.Caption,Item2.Caption))
  else begin
   ix := ColumnToSort - 1;
   Compare := CompareText(Item1.SubItems[ix],Item2.SubItems[ix]);
  end;
  if columnclicks mod 2 = 0 then compare:=not compare;
end;

procedure TForm1.ListView1ColumnClick(Sender: TObject;
  Column: TListColumn);
begin
  if ColumnToSort<>column.Index then columnclicks:=1
                                else inc(columnclicks);
  ColumnToSort := Column.Index;
  (Sender as TCustomListView).AlphaSort;
end;

Zahlen sortieren: comparetext vergleichtalphabetisch, du mußt bei oncompare das ganze in Zahlen (Strtoint - Achtung wenn es keine zahlen sind, wegen der exception) wandeln und die vergleichen. Du kannst ja columntosort abfragen und entscheiden, ob diese Spalte text oder zahlen enthält.

Mfg Frank

Moderiert von user profile iconTino: Delphi-Tags hinzugefügt.


Morduk666 - Mi 07.05.03 15:17

kewl kewl danke. nun funzts genau so wie ich wollte.
so hab ich nun zahlen sortiert:

Delphi-Quelltext
1:
Compare := CompareValue(strtoint(Item1.SubItems[i]), strtoint(Item2.SubItems[i]));                    

nur dreht er mir bei den zahlenspalten die sortierreihenfolge ned um. bei stringspalten funzt es einwandfrei. finde aber ned den fehler.

könnt mir da nochmal wer helfen ?

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Keldorn - Mi 07.05.03 15:23

die sortierreihenfolge habe ich ganz unten bei oncompare umgedreht. (compare := not compare)
wenn du deine zeile alleine hast, dann nimm compare := - comparevalue...
un bau ein try / except mit ein, damit du keine exception erhälst, wenn das subitem keine zahl enthält.

edit: nimmst du jetzt die CLX oder duoch die VCL, weil mit CLX hat das hier irgendwie nix zu tun ... :roll:


Morduk666 - Mi 07.05.03 15:56

Zitat:
edit: nimmst du jetzt die CLX oder duoch die VCL, weil mit CLX hat das hier irgendwie nix zu tun


keine ahnung ob CLX oder VCL. weis nedma was das is :p

aber meine zahlenspalten dreht er immer noch ned um. obwohl ich den selben code für string und integer spalten hab :

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
  
if ColumnToSort = 9 then
  begin
    i := ColumnToSort -1;
    Compare := CompareValue(strtoint(Item1.SubItems[i]), strtoint(Item2.SubItems[i]));
  end;

  if ColumnToSort = 10 then
  begin
    i := ColumnToSort -1;
   Compare := CompareText(Item1.SubItems[i],Item2.SubItems[i])  ;
  end;


if columnclicks mod 2 = 0 then compare:=not compare;

also spalte 10 geht auf und absteigend. aber die 9er mitden zahlen drinn ned.

bin ich blind ?? :(

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Keldorn - Mi 07.05.03 17:44

wenn du für Windows entwickelts ist es die VCL, für Linux die CLX.

denk dran, die spalten beginnen von 0 an zu zählen, nicht von 1.
d.h deine Spalte ganz links hat den "index" 0 und die 10. Saplte hat den index 9. setzt mal einen haltepunkt beim sortieren mit zahlen rein und gugg mal, ob der haltepunkt erreicht wird.

mfg Frank


Morduk666 - Mi 07.05.03 18:54

also ich mach das auf windows plattform.

Zitat:
setzt mal einen haltepunkt beim sortieren mit zahlen rein und gugg mal, ob der haltepunkt erreicht wird


also er kommt dort vorbei im code. er sortiert auch. aber nur absteigend. nie annersrum. und das betrifft nur die spalten mit integer werten. die string spalten funzen 1A


Keldorn - Do 08.05.03 09:27

Morduk666 hat folgendes geschrieben:
also ich mach das auf windows plattform.

dann bist du in der falschen Forums-Sparte...

Zitat:
also er kommt dort vorbei im code. er sortiert auch. aber nur absteigend. nie annersrum. und das betrifft nur die spalten mit integer werten. die string spalten funzen 1A


also comparevalue scheint es unter d5 nicht zu geben.
habs so gemacht:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  if zahlenspalte dann:
     try
      compare:= strtoint(Item1.SubItems[ix])-strtoint(Item2.SubItems[ix])
     except
      //im fehlerfalle, wenn die subitems keine zahl enthält oder dann comparetext wieder nehmen
      compare:=0;
     end;

und er hat mir die Spalten auf/absteigend sortiert.

Mfg Frank

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Morduk666 - Do 08.05.03 14:01

ey kewl super. nun funzts. vielen dank nochma für die mühe.

Zitat:
dann bist du in der falschen Forums-Sparte...


.. naja is n fall für den board admin ;p


Andreas Pfau - Sa 04.10.03 16:29

Hallo,

wenn ich Progs wie KaZaA oder so angucke, dann ist oben im ColumnHeader immer ein Dreieck, dass nach oben (absteigend sortiert) oder unten (aufsteigend sortiert) zeigt. Muss ich diese Dreieck-Grafik selber coden oder stellt Delphi da eine Lösung bereit?


Morduk666 - Sa 04.10.03 17:09

da gibts eine kompo. ElTree. die hat das und is free. damit geht listview und treeview. is ne feine kompo nutz ich immer ;)


Andreas Pfau - Sa 04.10.03 17:35

Vielen Dank, werd's mal austesten :D


Keldorn - Sa 04.10.03 18:06

Andreas Pfau hat folgendes geschrieben:
Hallo,

wenn ich Progs wie KaZaA oder so angucke, dann ist oben im ColumnHeader immer ein Dreieck, dass nach oben (absteigend sortiert) oder unten (aufsteigend sortiert) zeigt. Muss ich diese Dreieck-Grafik selber coden oder stellt Delphi da eine Lösung bereit?


smartimages im Columnheader verwenden oder den Header selberzeichnen.

Wenn du dir die Winapi-tuts von Luckie anguggst, ist da auch was bei den Demos (commonC/Listviwe) dabei.

Mfg Frank


Andreas Pfau - Sa 04.10.03 21:25

Hallo,

wow, das ist ja noch viel genialer... Danke! :D Wusste gar net, dass so eine Property existiert, aber das ist echt die ideale Lösung!


Keldorn - So 05.10.03 09:19

Andreas Pfau hat folgendes geschrieben:
Hallo,

wow, das ist ja noch viel genialer... Danke! :D Wusste gar net, dass so eine Property existiert, aber das ist echt die ideale Lösung!

naja, ideal finde ich sie persönlich nicht, da die Smallimages ja immer links sind und das sortiersymbol ist damit nicht rechts, wie man es von anderen Progs gewohnt ist. Einfach(er) ist es aber in jedem Fall :wink:


Andreas Pfau - So 05.10.03 09:57

Hallo,

ja, das fiel mir dann doch unangenehm auf. Aber, was soll's. Es muss ja nicht 110%ig sein, ist ja nur so 'ne Spielerei.


Tino - Mo 06.10.03 09:25

Morduk666 hat folgendes geschrieben:
.. naja is n fall für den board admin ;p

Oder ein Fall für einen Moderator. Oder besser vorher noch mal überlegen damit uns die Arbeit erspart bleibt. :wink:


TRomano - Mo 06.10.03 10:05

Unter http://www.lischke-online.de/ gibt es eine extrem schnelle und gute Compo namens "Virtual TreeView". Das Anschauen der sehr umfangreichen Quelltexte lohnt sich ...


Mackhack - Mi 19.01.05 03:40

Hi,

weis jemand warum man die 1. Spalte nicht absteigend A=>Z sortieren kann im ListView mit dem Sample von der Hilfe?


Delete - Mi 19.01.05 04:16

Nicht absteigend? In dem du die Berechnung umdrehst oder mal minus eins nimmst. Steht doch auch in der Hilfe.


Mackhack - Do 20.01.05 02:42

Luckie hat folgendes geschrieben:
Nicht absteigend? In dem du die Berechnung umdrehst oder mal minus eins nimmst. Steht doch auch in der Hilfe.


Sorry war ein versehen. Natürlich absteigend Z=>A


Delete - Do 20.01.05 02:47

Antwort ist die selbe.


Mackhack - Do 20.01.05 03:19

Luckie hat folgendes geschrieben:
Antwort ist die selbe.


Dachte ich mir :D


iKilledKenny - Mo 30.10.06 11:20

ich wollte keinen neuen topic aufmachen, deshalb hab ich den nochmal "aufgewärmt"...

sortieren funktioniert bei mir einwandfrei, solange ich keine spalten verschoben habe. nach verschiebung einer spalte ist kommt bei OnColumnClick für den Column-parameter irgendwas, aber nicht das, was ich angeklickt habe. hat da jemand eine idee?

p.s.: ich merke mir den spaltentyp im tag der column. nach einer verschiebung lass ich mir im OnColumnDragged die reihenfolge der tags ausgeben. da stimmt sie auch noch. nur im OnColumnClicked krieg ich dann den müll...

vielen dank für eure mühe.

grüße
alex


napsterforever - Do 02.07.09 00:21

bei mir kommt [Fehler] comunio_tool.pas(426): Undefinierter Bezeichner: 'ColumnToSort' ???


jaenicke - Do 02.07.09 00:28

Dann wirst du die Variable wohl nirgends deklariert haben...
Am sinnvollsten ist die als Feld unter private aufgehoben.


napsterforever - Do 02.07.09 00:58

wie muss ich das denn deklarieren?


jaenicke - Do 02.07.09 10:04

:gruebel:

Delphi-Quelltext
1:
2:
3:
4:
5:
  TForm...
  ...
  private
    ColumnToSort: Integer;
  end;


napsterforever - Do 02.07.09 11:26

hmm ok sieht jetzt so aus bei mir:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.liv_anzeige2ColumnClick(Sender: TObject;
  Column: TListColumn);
begin
  ColumnToSort := Column.Index;
  (Sender as TCustomListView).AlphaSort;
end;


procedure TForm1.liv_anzeige2Compare(Sender: TObject; Item1,
  Item2: TListItem; Data: Integer; var Compare: Integer);
var
  ix: Integer;
begin
  if ColumnToSort = 0 then
    Compare := CompareText(Item1.Caption,Item2.Caption)
  else begin
   ix := ColumnToSort - 1;
   Compare := CompareText(Item1.SubItems[ix],Item2.SubItems[ix]);
  end;

end;


wenn ich jetzt auf einen spaltenkopf klicke passiert aber nichts?!


jaenicke - Do 02.07.09 11:49

Das kann ich nicht reproduzieren. Die Ereignisse sind auch sicher verknüpft...?


napsterforever - Do 02.07.09 14:54

ja habe bei meiner listview (liv_anzeige2) bei ereignissen auf onColumnClick und OnCompare geklickt und dann die proceduren halt eingefügt!

aber mal ein ganz schlimmes anderes problem:
mein form ist weg?!?!

wenn ich die .dpr projektdatei öffne, öffnet sich zwar die formular-unit, aber der objektinspektor etc ist leer und das formular wird mir nicht anggezeigt, wenn ich dann starte bzw compiliere sagt er

Im Projekt xxx ist eine Exception der Klasse EResNotFound aufgetreten. Meldung 'Ressource TForm1 wurde nicht gefunden'. ...

die formular-unit ist aber wie gesagt vorhanden und die .dfm datei, wo die ganzen einstellungen der button und edits etc drin stehen, gibts auch noch, ABER WO IST MEINE FORM HILFE???


jaenicke - Do 02.07.09 15:18

Du hast direkt nach implementation diese Zeile entfernt...

Delphi-Quelltext
1:
{$R *.dfm}                    


napsterforever - Do 02.07.09 15:25

ja ist mir auch aufgefallen :D
aber wenn ich das wieder dahinschreibe, dann gehts immer noch nicht, es kommt ungülter eigenschaftswert

//EDIT: OMG ich hab sie wieder, kA wie ichs gemacht hab, aber sie ist wieder da puuuuh
jetzt nochmal versuchen ein zweites formular hinzuzufügen, aber diesmal vorher sichern xD