Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   VirtualTreeView und Sortieren (https://www.delphipraxis.net/207741-virtualtreeview-und-sortieren.html)

TurboMagic 28. Apr 2021 09:45

VirtualTreeView und Sortieren
 
Hallo,

ich benutze einen VirtualTreeView (VST) als Grid zur mehrspaltigen
Anzeige von Listeneinträgen (TList<T> mit Records als Einträgen.

Im GetText wird der anzuzeigende Listeneintrag über Node.Index ermittelt.

Nun würde ich auch gerne beim Klicken auf den Header einer Spalte nach
dieser sortieren, muss aber auch die ursprüngliche Sortierreihenfolge wieder
herstellen können.

Ich kenne jetzt 2 Möglichkeiten um im VST zu sortieren:

1. Ich sortiere im OnHeaderClick meine Liste um, das funktioniert, führt
aber dazu, dass ich eine Kopie meiner originalen Liste anfertigen und bei
späteren Änderungen durch den Benutzer (Editieren eines Eintrags, Löschen
oder hinzufügen) synchron halten muss.

2. Ich nutze OnCompareNodes des VST, da funktionierte aber die Ausgabe dann
nicht d.h. das sortieren schien keinen Effekt zu haben, da ich ja über
Node.Index den entsprechenden Listeneintrag im OnGetText ausgebe und somit
immer noch den selben ausgeben würde, da ja in meiner Liste immer noch alles
am selben Platz ist.

Würde es etwas bringen, den jeweiligen Eintrag (der müsste dann ein Objekt oder
ein Zeiger auf den Eintrag werden) als NodeData an den VST Knoten zu hängen?
Dann wäre das VST nicht mehr so wirklich virtuell benutzt, aber die Reihenfolge
meiner Listeneinträge würde immer gleich bleiben. OnGetText müsste sich dann halt
aus den NodeData die Daten ziehen.

Oder gibt's noch einen anderen Ansatz ohne großes Umbauen meines existierenden Codes?

Grüße
TurboMagic

KodeZwerg 28. Apr 2021 09:58

AW: VirtualTreeView und Sortieren
 
Ich frage mich, wenn ich das so lese, auf welche weise möchtest Du denn die original Reihenfolge wieder herstellen und wozu?
Per ColumnHeaderClick wird ja eine Sortierung durchgeführt, beim ersten mal aufsteigend danach absteigend (jedenfalls mache ich das so).

DieDolly 28. Apr 2021 10:09

AW: VirtualTreeView und Sortieren
 
Zitat:

1. Ich sortiere im OnHeaderClick meine Liste um, das funktioniert, führt
aber dazu, dass ich eine Kopie meiner originalen Liste anfertigen und bei
späteren Änderungen durch den Benutzer (Editieren eines Eintrags, Löschen
oder hinzufügen) synchron halten muss.
Das machst du aber umständlich.

Beim Sortieren eines VST braucht man keine Kopie der Daten anlegen. Das Node.Index ist auch egal, da es an einen Node gebunden ist.
Da braucht man keine doppelte Datenführung. Wenn ich eine Liste mit den Nodes A B C habe, die sortiere nach B A C und danach den ersten Node (B) auswähle, ist es trotzdem noch Node.Index=1 und nicht 0.

Poelser 28. Apr 2021 10:09

AW: VirtualTreeView und Sortieren
 
Moin,

ich hatte im VST mir mal so eine Lösung eingebaut:
Das Objekt, das im Tree angezeigt wird, um einen Integer erweitert. Dieser Wert wird in einer Spalte gespeichert, deren IsVisible auf False steht. Die sieht der Anwender also nicht.
Beim Füllen des Trees diesen Wert immer um eins erhöhen. Zusätzlich hatte ich dem Grid noch im Kontextmenü für den Header noch einen Eintrag "Original-Sortierung" spendiert, in dessen Action ich dann mit dieser unsichtbaren Spalte einen SortTree gemacht habe.
Source dafür habe ich jetzt leider keinen zur Hand, aber das Prinzip sollte verständlich sein.

TurboMagic 28. Apr 2021 10:46

AW: VirtualTreeView und Sortieren
 
Hallo,

sorry wenn ich die Antworten noch nicht so wirklich verstehe.
Daher hier noch mehr zum warum und was ich aus euren Antworten entnehme.

1. Die Daten stammen aus einer Datei und müssen in bestimmten Szenarien in
der Reihenfolge verarbeitet werden, in der die in der Datei stehen.
Wenn jetzt jemand zu Anzeigezwecken die Liste sortiert darf das keinen
Einfluss auf die ursprüngliche Reihenfolge haben. Die muss man beim
Speichern wieder zur Verfügung haben.

2. @DieDolly: bisher habe ich meine Daten nur über Node.Index = Index
des Listeneintrags mit dem VST verknüpft. Ich vermute also, dass ich
nicht um die Nutzung von Node.GetData/SetData herumkommen werde wenn
ich nicht meine Datenhaltung bei Klicken des Nutzers sortiere sondern
das CompareNode vom VST nutzen würde.

3. @Poelsker: du hättest mit deinem Ansatz eine fortlaufende Nummer nach
der du vor dem Speichern sortieren könntest. Das müsste dazu noch nicht
mal als versteckte Spalte ins VST. Du musst dir nur die jeweils höchste ID
merken um beim Hinzufügen von Einträgen neue Nummern vergeben zu können.
Klingt gut!

Danke mal für alle diese Ideen. Ich glaube das bringt mich gedanklich etwas
weiter.

Grüße
TurboMagic

DieDolly 28. Apr 2021 11:05

AW: VirtualTreeView und Sortieren
 
Zitat:

Wenn jetzt jemand zu Anzeigezwecken die Liste sortiert darf das keinen
Einfluss auf die ursprüngliche Reihenfolge haben.
Wenn du deine Nodes in einer Liste hast und diese Liste abarbeitest/ansprichst, was hoffentlich der Fall ist, hat es keinen Einfluss auf die Reihenfolge.

Poelser 28. Apr 2021 11:33

AW: VirtualTreeView und Sortieren
 
Zitat:

Zitat von TurboMagic (Beitrag 1488061)
3. @Poelser: du hättest mit deinem Ansatz eine fortlaufende Nummer nach
der du vor dem Speichern sortieren könntest. Das müsste dazu noch nicht
mal als versteckte Spalte ins VST. Du musst dir nur die jeweils höchste ID
merken um beim Hinzufügen von Einträgen neue Nummern vergeben zu können.
Klingt gut!

Ja klar, zum Hinzufügen von Knoten reicht das natürlich. Wer zu spät kommt, stellt sich natürlich hinten an! :)

DieDolly 28. Apr 2021 11:36

AW: VirtualTreeView und Sortieren
 
Wieso macht ihr das soi kompliziert?

Aviator 28. Apr 2021 11:43

AW: VirtualTreeView und Sortieren
 
Moin zusammen.

Warum so umständlich mit zusätzlichem Index und Spalte und was weiß ich nicht alles? Beim Erstellen der Node wird als NodeData einfach der Pointer auf das Objekt oder auf den Index in der
Delphi-Quellcode:
TObjectList<T>
an die Node übergeben. Somit ändert sich beim Sortieren für deine Daten gar nichts. Der NodeIndex wird zwar verändert, aber der interessiert dich dann nicht mehr. Die Daten werden in der Liste vorgehalten was auch dazu führt, dass du deinen VST beliebig oft leeren und wieder füllen kannst.

Unter keinen Umständen darfst du die Node-Daten mit einem Index oder einem Wert verknüpfen, der sich beim Ändern der Anzeige ebenfalls ändert und plötzlich dazu führt, dass Daten falsch angezeigt werden.

Das Sortieren des Trees solltest du im
Delphi-Quellcode:
OnCompareNode()
Event durchführen. Damit bleibt es dir überlassen nach welchen Kriterien du sortieren willst. Eventuell willst du ja beim Klick auf Spalte 1 zusätzlich noch nach Spalte 2 sortieren wenn in Spalte 1 identische Werte vorkommen können usw. Ausgelöst wird der Sortiervorgang aber über das
Delphi-Quellcode:
OnHeaderClick()
Event. Darin kannst du dann auch die SortDirection der Column angeben, sodass der bekannte Sortierpfeil rechts vom ColumnTitle erscheint.

Alles in allem hast du hier den Vorteil, dass du auch die Anzeige von deinen Daten weitestgehend getrennt hast. Bis auf die Verknüpfung der Node mit dem Index in der
Delphi-Quellcode:
TObjectList<T>
. Aber irgendwo muss ja eine Verbindung hergestellt werden.

TurboMagic 28. Apr 2021 12:23

AW: VirtualTreeView und Sortieren
 
Ok, das mit dem Index als NodeData statt eines richtigen Pointers finde ich schon besser.
Dann kann man auch problemlos CompareNode zum sortieren benutzen.

generic 5. Mai 2021 08:32

AW: VirtualTreeView und Sortieren
 
Mal paar andere Gedanken:

Vermischt ihr nicht die Geschäftslogik also die TObjectList mit einer Möglichen Darstellung (VST)?

Programmier doch dein Programm erstmal so, dass es mit der OL läuft.

Die Oberfläche kannst du später anbauen indem du die Ereignisse der OL nutzt.
Die Darstellung/Sortierung in der UI sollte mit dem BI wenig zu tun haben.
Warum sollte die UI einen Schlüssel/Index erzeugen, welcher später in der BI gebraucht wird?

Du kannst auch deine Objekte als Data in den Baum hängen.
Hab ich beim Stammtisch #2 gezeigt:
https://www.delphipraxis.net/712774-post4.html
https://www.delphipraxis.net/104896-...-nachtrag.html

TiGü 5. Mai 2021 12:20

AW: VirtualTreeView und Sortieren
 
Du kannst auch mit Objekten und zwei Listen arbeiten.
Eine Original-Liste 1 und eine weitere Liste 2, die zum Sortieren da ist.
Die weitere Liste 2 hat die selben (!) Items wie die Original-Liste (gleiche Zeiger), wird also initial mit dem Items von der Original-Liste 1 gefüllt.

Sobald du von außen sagst:
Sortiere nach Kriterium so und so, sortierst du auf der weiteren Liste 2 wie du magst und wechselst dann ggf. die RootNodeCount und den die Quelle für OnGetText und die anderen Events.

Ich verstecke das zumeist in einer Klasse, die beide Listen hält und eine Property für die aktuell zu verwendende Liste nach außen hin zum Formular mit der TVirtualTreeView gibt.
Je nachdem gibt der Getter dann die Original-Liste 1 oder weitere Liste 2 zurück.

joachimd 5. Mai 2021 13:03

AW: VirtualTreeView und Sortieren
 
Zitat:

Zitat von TiGü (Beitrag 1488637)
Du kannst auch mit Objekten und zwei Listen arbeiten.

Dann solltest Du aber statt mit Objekten mit Interfaces arbeiten ... damit gibt es weniger Speicherprobleme.

himitsu 5. Mai 2021 13:08

AW: VirtualTreeView und Sortieren
 
Die zwei Liste braucht nicht Owner zu sein.
So lange nur einer Owner ist, gibt es praktisch auch keine Probleme.

Alternativ kann die zweite Liste aber auch nur die Indize zur ersten Liste zu enthalten, anstatt die Objekte selbst.

Man könnte in die Objekte auch ein zusätzliches Feld aufnehmen und dort nach dem Datenladen den ursprünglichen Index speichern.
Oder man nimmst die zweite Liste nicht für die Sortierung, sondern verwendet weiterhin die erste Liste. In der zweiten Liste kann man die ursprüngliche Sortierung speichern (nach dem Datenladen), entweder die Objektzeiger direkt oder z.B. eine ID aus den Objekten.
Und das nimmt man dann, wenn man die Sortierung zurücksetzen will.

Oder ganz einfach (aber bissl langsamer) ... die Daten einfach neu laden, dann ist die Sortierung auch wieder original. :stupid:

TiGü 5. Mai 2021 13:31

AW: VirtualTreeView und Sortieren
 
Zitat:

Zitat von joachimd (Beitrag 1488641)
Zitat:

Zitat von TiGü (Beitrag 1488637)
Du kannst auch mit Objekten und zwei Listen arbeiten.

Dann solltest Du aber statt mit Objekten mit Interfaces arbeiten ... damit gibt es weniger Speicherprobleme.

Wie Himi sagt:
Eine TObjectList<T>.Create(True) und eine andere TObjectList<T>.Create(False) (oder gleich TList<T>) und schon ist der Lachs gegessen.
Interfaces kann man machen, ist aber nicht notwendig für reine Datenobjekte zur Anzeige in der (Virtual)Treeview.

haentschman 5. Mai 2021 13:40

AW: VirtualTreeView und Sortieren
 
Zitat:

Eine TObjectList<T>.Create(True) und eine andere TObjectList<T>.Create(False) (oder gleich TList<T>) und schon ist der Lachs gegessen.
...der ist aber verbrannt. :zwinker:

Zitat:

Beim Erstellen der Node wird als NodeData einfach der Pointer auf das Objekt oder auf den Index in der TObjectList<T> an die Node übergeben. Somit ändert sich beim Sortieren für deine Daten gar nichts.
+1 :thumb:

Die Darstellung sollte nicht den Inhalt der Datenhaltung beeinflussen. :warn:

himitsu 5. Mai 2021 13:55

AW: VirtualTreeView und Sortieren
 
In NodeData kann man auch den Index oder eine ID speichern, um für die Anzeige die Daten aus der Liste (nicht direkt aus dem Objektzeiger) zu holen.

Es kommt aber immer auf die Umstände drauf an.

* Index ist blöd, wenn die Liste sich ändern kann (mittendrin ... am Ende Neues hinzu ist egal, da die anderen Indize sich nicht ändern)

* ID geht eigentlich immer (die ID ist natürlich mit den Daten und nicht dem Objekt verknüpft, falls Dieses sich mal ändern kann, siehe nachfolgend)

* ein Objektzeiger direkt speichern kann auch manchmal nachteilig sein
* * wenn z.B. die Liste bei Änderung ein neues Objekt erstellt und jenes in der Liste austauscht
* * hier würde ID und vielleicht Index noch passen, aber der Zeiger aufs "alte" Objekt wäre nun ungültig

TurboMagic 6. Mai 2021 07:18

AW: VirtualTreeView und Sortieren
 
Hallo,

hier noch eine umsetzungstechnische Frage, da ich eh' noch nicht zur Umsetzung gekommen bin.
Angenommen ich würde die Lösung nutzen wollen, bei der im NodeData der Index meines anzuzeigenden
Listeneintrags steht, wie/wann bekomme ich das rein?

1. Ich lade meine Daten in meine Liste
2. Ich setze den RootNodeCount des VST auf Liste.Count
3. Bisher hab' ich im GetNodeText über den Knotenindex den Listeneintrag geholt.
Das wäre ja umzustellen. Nur wann schreibt man den Index in NodeData?
Da gibt's glaube ich im VST ein initialisierungs Event?
4. Nur: dieses Event wird wohl für jeden Knoten dann aufgerufen, wenn er das erste mal anzuzeigen
ist. Oder? Falls ja, was ist, wenn jemand noch nicht bis zum Listenende gescrollt hatte aber
schon das Sortieren auslöst?
5. Füge ich später Daten zur Liste hinzu (am Ende) kann ich in diesem initialisierungsevent einfach
wieder über den VST Node.Index das NodeData initialisieren, oder?
6. Problematisch kann es werden, wenn jemand Listeneinträge löscht. Dann müsste ich durch alle
VST Knoten durch und ab dem Index des gelöschten alle Indizes um 1 erniedrigen. Da Multiselekt
möglich ist, wird's noch etwas schwieriger...

Grüße
TurboMagic

TiGü 6. Mai 2021 10:25

AW: VirtualTreeView und Sortieren
 
Probiere meinen Vorschlag, dann hast du keinen Trouble und wirst heute noch fertig.

jus 6. Mai 2021 11:11

AW: VirtualTreeView und Sortieren
 
Zitat:

Zitat von generic (Beitrag 1488606)
Mal paar andere Gedanken:

Vermischt ihr nicht die Geschäftslogik also die TObjectList mit einer Möglichen Darstellung (VST)?

Programmier doch dein Programm erstmal so, dass es mit der OL läuft.

Die Oberfläche kannst du später anbauen indem du die Ereignisse der OL nutzt.
Die Darstellung/Sortierung in der UI sollte mit dem BI wenig zu tun haben.
Warum sollte die UI einen Schlüssel/Index erzeugen, welcher später in der BI gebraucht wird?

Du kannst auch deine Objekte als Data in den Baum hängen.
Hab ich beim Stammtisch #2 gezeigt:
https://www.delphipraxis.net/712774-post4.html
https://www.delphipraxis.net/104896-...-nachtrag.html

Wo findet man noch das dazugehörige Stammtisch #2 Video?

mytbo 6. Mai 2021 14:11

AW: VirtualTreeView und Sortieren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe dir mal eine Unit angehängt, die noch den direkten Umgang mit einem TVirtualStringTree aus einem sehr alten Projekt von mir zeigt. So was mache ich schon lange nicht mehr, sondern verwende einen Mediator. Behandelt werden die Events: InitNode, FreeNode, GetText, PaintText, BeforeItemErase, CompareNodes, HeaderClick, ContextPopup, Checked. Zu beachten ist, dass es sich um eine alte Version des VirtualStringTrees handeln muss. Die Events könnten heute etwas anders aussehen. Vielleicht hilft es dir.

Bis bald...
Thomas


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:30 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