![]() |
VirtualSourceTree selektierte Nodes löschen?
Ich habe folgenden Code geschrieben, um selektierte Nodes zu löschen
Delphi-Quellcode:
Das funktioniert wunderbar. Aber selektiert man nun auch den ersten Node, dann geht das in die Hose.
var
Node, NodeTmp: PVirtualNode; i: Integer; begin Node := VST.GetFirst; while Assigned(Node) do begin if VST.Selected[Node] then begin NodeTmp := VST.GetPreviousSibling(Node); VST.DeleteNode(Node); Node := NodeTmp; end; Node := VST.GetNextSibling(Node); // ich brauche nur Toplevel Nodes end; end; Ich habe gelesen, dass man den aktuellen Node zwischenspeichern muss, um später GetNextSibling() ausführen zu können. Denn beim Löschen von Node geht die Referenz auf diesen verloren was zu einer AV führt. Gibt es eine schönere Möglichkeit durch alles Nodes zu laufen und die selektierten zu löschen? Wichtig ist, dass ich das alles per Hand machen muss. Einen Einzeiler kann ich, wenn es den gibt, leider nicht verwenden. 0815 wäre eventuell sogar noch... aber ist das noch konform?
Delphi-Quellcode:
var
Data: TVSTData; i: Integer; NodeArray: TNodeArray; begin NodeArray := VST.GetSortedSelection(False); for i := Low(NodeArray) to High(NodeArray) do begin VST.DeleteNode(NodeArray[i]); // Node "visuell" löschen end; |
AW: VirtualSourceTree selektierte Nodes löschen?
EDIT: Oha. Ich sollte deinen Beitrag komplett lesen. Da zeigst du ja primzipiell schon die (von dir als 0815 bezeichnet) Lösung mehr oder weniger auf. Schau mal die
Delphi-Quellcode:
Funktion an. Dort wird das auch gemacht.
DeleteSelectedNodes()
Um ehrlich zu sein habe ich noch nie Nodes in einer Schleife löschen müssen. Aber nichts desto trotz verstehe ich diese Aussage nicht: Zitat:
Delphi-Quellcode:
.
VirtualTreeView1.DeleteSelectedNodes
Zur Not schaust du dir die Funktion im SourceCode des Trees an und baust die nach. Ich kann nur wirklich nichts dazu sagen, ob dann wirklich Referenzen verloren gingen. Aber es wäre nur logisch. Aber schau dir mal die Funktion
Delphi-Quellcode:
an. Die wird auch intern im Tree verwendet wenn du
TBaseVirtualTree.GetSortedSelection()
Delphi-Quellcode:
aufrufst.
DeleteSelectedNodes()
|
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Ich möchte neben dem VST noch eine ObjectListe führen, welche die Daten hält. Denn ab und zu möchte ich nur gewisse Nodes anzeigen, trotzdem aber Zugriff auf alle haben und das geht nur mit einer Liste. GetSortedSelection mit einer for-Schleife ist interessant und, wie ich finde, besser als eine while-Schleife und Assigned()-Prüfung. Das funktioniert jetzt erstmal wunderbar. Ich danke für die Hilfe bisher (auch im anderen Thema). Mein Umbau von TListView zu VST wird sicher noch viel zeit in Anspruch nehmen und es werden sicher noch mehr Fragen auftauchen. Alles aber zu seiner Zeit. |
AW: VirtualSourceTree selektierte Nodes löschen?
Wenn du mit nicht immer alle anzeigen einen Filter meinst... Dafür gibt es Visible. Damit kannst du Knoten sichtbar und unsichtbar machen und damit extrem schnell live bei der Eingabe filtern.
|
AW: VirtualSourceTree selektierte Nodes löschen?
Ich mach das immer so:
|
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Bei DeleteNode wird dann OnFreeNode aufgerufen. |
AW: VirtualSourceTree selektierte Nodes löschen?
Ohne das jetzt probiert zu haben, wäre diese vereinfachte Form deines ursprünglichen Ansatzes nicht vollkommen ausreichend?
Delphi-Quellcode:
Node := VST.GetFirst;
while Assigned(Node) do begin NodeTmp := VST.GetNextSibling(Node); if VST.Selected[Node] then begin VST.DeleteNode(Node); end; Node := NodeTmp; end; |
AW: VirtualSourceTree selektierte Nodes löschen?
(Siehe Edit)
Ungefähr so? => ObjectList OwnObjects auf Fale => Änderung von Uwe eingebaut und
Delphi-Quellcode:
Danach wird mir noch immer "Count: N ausgegeben" (N = die Anzahl der Nodes vor dem Löschen)
procedure TForm2.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var Data: TVSTData; idx: Integer; begin Data := Node.GetData<TVSTData>; idx := aVSTDataClasses.IndexOf(Data); if idx > -1 then aVSTDataClasses.Items[idx].Free; // Data.Free; end;
Delphi-Quellcode:
ShowMessage('Count: ' + IntToStr(aVSTDataClasses.Count));
Edit Dummheit muss bestraft werden.
Delphi-Quellcode:
und nicht
aVSTDataClasses.Delete(idx);
Delphi-Quellcode:
.
aVSTDataClasses.Items[idx].Free;
|
AW: VirtualSourceTree selektierte Nodes löschen?
Auch wenn das
Delphi-Quellcode:
an der Stelle nicht passt hier noch ein kleiner Tipp:
aVSTDataClasses.Items[idx].Free;
Du kannst das
Delphi-Quellcode:
getrost weglassen und einfach
.Items
Delphi-Quellcode:
schreiben. Items ist die Standardeigenschaft einer Liste. Somit ist das überflüssig.
aVSTDataClasses[idx].Free;
Und die Vorteile die du davon hast sind:
|
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
|
AW: VirtualSourceTree selektierte Nodes löschen?
Das weiß ich nicht aber beim Schließen der Demo habe ich keinerlei Memory-leaks.
Ich gehe einfach mal davon aus, dass weil ja jetzt das VST die Speicherverwaltung übernimmt, hier die Instanz beim Aufruf von Data.Free freigegeben wird. |
AW: VirtualSourceTree selektierte Nodes löschen?
Das ist aber ganz schlecht, wenn Du das nicht weißt. Da können schon kleinere Änderungen am Code entweder zu MemoryLeaks oder zu AVs führen. Ich spreche da aus Erfahrung.
|
AW: VirtualSourceTree selektierte Nodes löschen?
Wie oben geschrieben gehe ich davon aus, dass das VST das jetzt übernimmt, da die ObjectList ja die Daten nicht mehr erbt.
Wenn dem nicht so ist, kannst du mich gerne erschlagen. Aber selbst wenn ich im OnFreeNode aVSTDataClasses.Delete(idx); weglasse bekomme ich keine Speicherlecks. |
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Delphi-Quellcode:
ist nebenbei bemerkt keine sehr schnelle Operation und kann bei extrem vielen Nodes deine Performance schon ziemlich verschlechtern. Hat es irgendeinen Grund, warum du die Objekte überhaupt in einer
IndexOf
Delphi-Quellcode:
ablegst? Ich persönlich gehe immer so vor, dass ich beim Einfügen einer Node mein Datenobjekt/Datenrecord mit
TObjectList
Delphi-Quellcode:
erstelle und zuweise. Im
Create
Delphi-Quellcode:
hole ich mir dann mit
OnFreeNode
Delphi-Quellcode:
den direkten Zeiger auf das Objekt und gebe es dort entsprechend mit
GetNodeData
Delphi-Quellcode:
wieder frei.
Free
Oft bietet es sich sogar an mit Records zu arbeiten. Dort musst du zu Begin einmal
Delphi-Quellcode:
setzen. In diesem Falle verwaltet der VST den Speicher tatsächlich vollkommen von alleine. Lediglich ein
NodeDataSize := SizeOf(TDataRecord)
Delphi-Quellcode:
im
Finalize
Delphi-Quellcode:
ist teilweise erforderlich (wenn dein Records Strings, Interfaces oder andere managed types enthält).
OnFreeNode
|
AW: VirtualSourceTree selektierte Nodes löschen?
Wir drehen uns im Kreis.
|
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Was ist denn jetzt richtiger? Mir ist nur wichtig, dass ich immer vollen Zugriff auf alle Daten habe. Daher dachte ich, wäre eine ObjectList nicht schlecht. Zitat:
Zitat:
Delphi-Quellcode:
Und so erzeuge ich meine Nodes
// ObjectList mit OwnObjects auf FALSE
procedure TForm2.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var Data: TVSTData; idx: Integer; begin Data := Node.GetData<TVSTData>; idx := aVSTDataClasses.IndexOf(Data); if idx > -1 then aVSTDataClasses.Delete(idx); Data.Free; end;
Delphi-Quellcode:
type
TVSTData = class(TObject) Col1, Col2, Col3, Col4, Col5, sDescription: string; Icon: Byte; end; TVSTDataClasses = TObjectList<TVSTData>; var aVSTDataClasses: TVSTDataClasses; ... procedure TForm2.Button1Click(Sender: TObject); var aVSTData: TVSTData; i: Integer; begin if not Assigned(aVSTDataClasses) then aVSTDataClasses := TVSTDataClasses.Create(False); for i := 0 to 5 do begin aVSTData := TVSTData.Create; aVSTData.Col1 := IntToStr(i); aVSTData.Col2 := IntToStr(Random(1000)); aVSTData.Col3 := IntToStr(Random(1000)); aVSTData.Col4 := IntToStr(Random(1000)); aVSTData.Col5 := IntToStr(Random(1000)); aVSTData.Icon := Random(ImageList2.Count - 1); if i mod 3 = 0 then aVSTData.sDescription := 'Das ist ein ganz langer String - ok so lang ist er nicht!' else aVSTData.sDescription := ''; aVSTDataClasses.Add(aVSTData); end; VST.RootNodeCount := aVSTDataClasses.Count; end; |
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Zitat:
|
AW: VirtualSourceTree selektierte Nodes löschen?
Ehrlich gesagt - ich weiß es nicht ;)
Am liebsten würde ich die Daten direkt im Node speichern aber das macht man ja wohl auch nicht. Pointer-Gefummel möchte ich nicht mehr. |
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Delphi-Quellcode:
und einmal residiert der Zeiger in der
GetNodeData
Delphi-Quellcode:
. Dein
TObjectList
Delphi-Quellcode:
bezieht sich ja aber trotzdem auf das konkrete Objekt.
Free
Delphi-Quellcode:
macht das Gleiche wie
Data := Node.GetData<TVSTData>;
... Data.Free;
Delphi-Quellcode:
aVSTDataClasses[aVSTDataClasses.IndexOf(Data)].Free
|
AW: VirtualSourceTree selektierte Nodes löschen?
Dann ist das also doch so wie ich vermutet habe.
Deine Methode mit den Records, hat die irgendwelche Vorteile gegenüber einer TObjectList mit einer Klasseninstanze pro Node/Datensatz? Am Rande. Wenn ich OwnObjects auf False habe, dann kann auch auch genau so gut eine TList nehmen und mit die paar Byates overhead sparen :P |
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Delphi-Quellcode:
/
Create
Delphi-Quellcode:
. Im Grunde eher Geschmackssache.
Free
Die eigentliche Frage ist: benötigst du bidirektionalen Zugriff auf die Daten? Also musst du an irgendeiner Stelle mal die Daten im Datenobjekt modifizieren, ohne die dazugehörige Node zu kennen. In diesem Falle würde die ObjektList bzw. Sinn machen. Trifft das nicht zu, würde ich mir die Liste komplett sparen. Ob du weiter bei Objekten bleibst, oder Records nimmst, macht hier allerdings keinen wirklichen Unterschied. |
AW: VirtualSourceTree selektierte Nodes löschen?
Zugriff ohne die Nodes zu kennen und ohne auf die visuelle Komponente zugreifen zu müssen, wäre schon nicht schlecht.
Das Schöne daran ist, dass ich in der Liste arbeiten kann und das VirtualStringTree im GetText-Event meine Änderungen übernimmt - und ich habe nicht das VST angefasst. Das heißt ich glaube ich könnte aus einem TThread heraus Strings in der Liste ändern ohne synchronisieren zu müssen. Naja ist nur eine Vermutung ohne wirklichen Sinn dahinter. Was mir nur wichtig ist, ist der Zugriff auf die Liste und das Abändern der Daten ohne das VST anfassen zu müssen. |
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Delphi-Quellcode:
zeigt, damit du nach Datenänderungen von außerhalb noch ein
PVirtualTreeNode
Delphi-Quellcode:
aufrufen kannst. Das ist erforderlich, damit die Node neu gezeichnet wird (und somit deine Änderungen visuell übernommen werden). Zumindest wenn du keinen Full Refresh durchführen willst.
VST.Update(Data.Node)
|
AW: VirtualSourceTree selektierte Nodes löschen?
Am Ende hat er "kein" Speicherleck, da er ja die TObjectList frei gibt, welche auch alle Ojekte mit nimmt (OwnsObjects=True :?:), welche nicht von dem VT freigegeben wurden.
Problem wäre jetzt, wenn der VT die Ojekte frei gibt, wenn man sie den Nodes bekannt macht und dann in der ObjectList ungülige Zeiger zurück bleiben, welche man die ObjectList dann natürlich nicht freigeben lassen sollte. |
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Zitat:
Wenn ich raten müsste würde ich vielleicht sowas wie
Delphi-Quellcode:
im InitNode ausführen lassen wobei aNode ein PVirtualNode ist.
aVSTDataClasses[Node.Index].aNode := Node;
Kann es sein, dass du statt VST.Update() eventuell VST.InvalidateNode() meinst? |
AW: VirtualSourceTree selektierte Nodes löschen?
[meine Meinung]
Bei so vielen Meinungen meine noch dazu...:P Zitat:
Zitat:
Sinngemäß: Stell dir mal vor, das dir der VST nicht mehr gefällt und die Daten anders angezeigt werden sollen. An der Datenhaltung ändert sich nichts. Mit der Objektlist ist die Anzeige der Daten (GUI) von der Datenhaltung getrennt. :thumb: [/meine Meinung] |
AW: VirtualSourceTree selektierte Nodes löschen?
Liste der Anhänge anzeigen (Anzahl: 1)
Hier ist der Source meiner kleinen, super-schlechten Demo. Ich hoffe die Buttons sind trotzdem verständlich und der Code ist nicht all zu schlecht.
Ich habe versucht eure Vorschläge umzusetzen und das ist das Ergebnis. |
AW: VirtualSourceTree selektierte Nodes löschen?
Zitat:
Delphi-Quellcode:
und
RootNodeCount
Delphi-Quellcode:
). Manuelles Hinzufügen/Löschen von Nodes (wie es der Threadersteller momentan betreibt) ist nichts anderes als die Modellierung einer Datenstruktur auf Basis des visuellen Controls. Von daher finde ich die Verwendung von Records hier in keinster Weise besser oder schlechter, als die Verwendung von Objekten.
OnInitNode
Klar, die Objekte sind theoretisch unabhängig in ihrer
Delphi-Quellcode:
, aber in der Praxis bringt das doch absolut keinen Vorteil, wenn zusätzlich die Struktur nicht auch dort abgebildet wird (was nicht der Fall ist). Möchte ich vom VST auf ein anderes Control umsteigen, dann weiß ich - im Falle eines Baumes - noch lange nicht, in welcher Hierachie die einzelnen Objekte anzuordnen sind. Und selbst, wenn es nur eine einfache Liste ist, wiederspricht das manuelle Hinzufügen/Löschen von Nodes immer noch dem "virtual" Paradigma und degradiert das Control im Grunde zu einem normalen List/TreeView. Deshalb gewinnt in meiner Abwägung hier das KISS Prinzip gegenüber der absolut korrekten Trennung von Daten und GUI.
TObjectList
Noch als Ergänzung: Ich habe mich in letzter Zeit recht intensiv mit der Abbildung von Datenstrukturen auf (virtuellen) Bäumen beschäftigt. Hierbei ist es auch so, dass ich eine Baumstruktur in einer seperaten Datenstruktur vorliegen habe - komplett unabhängig von visuellen Controls, ganz wie es sich gehört. Jetzt habe ich versucht diese Struktur visuell abzubilden und mich in diesem Zusammenhang mit der
Delphi-Quellcode:
beschäftigt. Vielleicht liegt es an meiner mangelnden Erfahrung mit dieser speziellen Komponente, aber die Geschichte hatte diverse Tücken, wenn man einzelne Objekte aus der Datenstruktur entfernen wollte.
TcxVirtualTreeList
Letztlich bin ich dann auch wieder weg vom virtuellen Prinzip und habe stattdessen meine Datenstruktur um Events (CreateNode, InsertNode, RemoveNode, DestroyNode) erweitert. In den entsprechenden Event-Handlern implementiere ich dann AddChild, Move und Delete auf dem gewünschten visuellen Control. Das wäre zumindest eine Möglichkeit der korrekten Trennung; wobei ich persönlich es in diesem Falle wie gesagt einfach für Overkill halte. |
AW: VirtualSourceTree selektierte Nodes löschen?
Das lässt mich nachdenken.
Wäre es möglich wenn sich beide Parteien meine Demo ansehen und dann entscheiden ob das so in Ordnung ist? Mein Ziel ist es, dass ich von verschiedenen Stellen im Programm Zugriff auf die Daten habe. Aktuell ist es ECHT FIES! Ich schnappe mir die TreeView-Caption, öffne eine Ini-Datei, lade die Section und lese Daten aus. Das wäre mit VST mit und/oder ohne TList nicht mehr der Fall. |
AW: VirtualSourceTree selektierte Nodes löschen?
Ich denke Du kannst wirklich eine TObjectlist benutzen,
aber dann ist es wichtig festzulegen wem die Daten "gehören". In diesem Fall der Liste. Änderungen die ich gemacht habe: Typ geändert: TVSTDataClasses = TObjectList<TVSTData>; das erzeugen von aVSTDataClasses habe ich in das FormCreate verschoben
Delphi-Quellcode:
Im Button1Click habe ich das erzeugen der Liste entfernt.
ReportMemoryLeaksOnShutdown := True;
aVSTDataClasses := TVSTDataClasses.Create; Zusätzlich FormDestroy
Delphi-Quellcode:
Das freenode umgebaut auf:
procedure TForm2.FormDestroy(Sender: TObject);
begin aVSTDataClasses.free; end;
Delphi-Quellcode:
Button3Click:
procedure TForm2.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin // Das aber nur wenn wirklich die Daten aus der Liste weg sollen!!!! aVSTDataClasses.remove(node.GetData<TVSTData>); end;
Delphi-Quellcode:
procedure TForm2.Button3Click(Sender: TObject);
begin // Hier muss auf jeden Fall der VST gecleared werden VST.Clear; // Jetzt sollte aVSTDataClasses.count 0 sein wenn im VSTFreeNode der Eintrag gelöscht wird // Nur notwendig wenn im VSTFreeNode die nodes nicht freigegeben werden aVSTDataClasses.Clear; end; Umbau des Button5Click
Delphi-Quellcode:
procedure TForm2.Button5Click(Sender: TObject);
var Node, NodeTmp: PVirtualNode; begin Node := VST.GetFirstSelected; while Assigned(Node) do begin NodeTmp := VST.GetNextSelected(Node); VST.DeleteNode(Node); Node := NodeTmp; end; end; |
AW: VirtualSourceTree selektierte Nodes löschen?
Mh auch nicht schlecht.
Heißt also, die Daten werden von der Liste verwaltet und man braucht nur eine einzige Zeile aufrufen, um einen Node + Daten zu löschen. |
AW: VirtualSourceTree selektierte Nodes löschen?
Ja, davon reden wir schon seit Tagen.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:34 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