![]() |
Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ich füge aktuell einer VirtualStringTree einiges An Einträgen hinzu.
Ungefähr so
Delphi-Quellcode:
Mein Record ist ein ganz normales Record
procedure AddVSTStructure(aVST: TVirtualStringTree; aRecord: TTreeData);
var Data: PTreeData; Node: PVirtualNode; begin Node := aVST.AddChild(nil); Node.CheckType := ctCheckBox; Node.CheckState := csCheckedNormal; Data := aVST.GetNodeData(Node); Data^ := aRecord; end;
Delphi-Quellcode:
Das Hinzufügen dauert komischerweise recht lange, obwohl VirtualStringTree1.BeginUpdate und VirtualStringTree1.EndUpdate schon gesetzt sind.
type
PTreeData = ^TTreeData; TTreeData = record iIndex: Integer; // Hier stehen ein paar Variablen.. Strings, Boolean etc end; Ist das normal, dass das bei 100000 Einträgen und mehr in etwa 10 Sekunden dauert? |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Dann musst du umstellen. Setze den RootNodeCount des Trees auf den gewünschten Wert und benutze die Events
Delphi-Quellcode:
und
OnInitNode()
Delphi-Quellcode:
. Beispiele kann ich aktuell nicht machen. Erst so in 2 Stunden wieder.
OnInitChildren()
Lies dir auch mal den großen Kommentar zu AddChild() durch den Mike Lischke drüber geschrieben hat. Die Funktion sollte man eigentlich nicht verwenden. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ist es schlimm, wenn der RootNodeCount höher ist als die Anzahl der Nodes die danach angezeigt werden?
Denn ich sehe gerade erst, dass ich tatsächlich nirgendwo RootNodeCount setze! |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Es geht noch einmal deutlich schneller, wenn du mit Klassen statt mit Records arbeitest. Beim Hinzufügen wie du es jetzt machst wird der Record einmal bei der Übergabe an AddVSTStructure und einmal beim Zuweisen an den Knoten komplett kopiert.
Wenn du hingegen eine Klasse benutzt, wird nur der Pointer kopiert. Damit habe ich 1 Million Einträge in 2 Sekunden hinzugefügt. Komplettes Beispiel:
Delphi-Quellcode:
NodeCount für den Knoten setzen und später initialisieren geht natürlich noch schneller, ist aber meist auch etwas aufwendiger.
type
TTest = class private FTestProperty: string; public constructor Create(const AValue: string); property TestProperty: string read FTestProperty write FTestProperty; end; TForm103 = class(TForm) VirtualStringTree1: TVirtualStringTree; Button1: TButton; procedure Button1Click(Sender: TObject); procedure VirtualStringTree1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure VirtualStringTree1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); private { Private-Deklarationen } public { Public-Deklarationen } end; //... procedure TForm103.Button1Click(Sender: TObject); var i: Integer; begin VirtualStringTree1.BeginUpdate; try for i := 1 to 1000000 do VirtualStringTree1.AddChild(nil, TTest.Create('Knoten ' + IntToStr(i))) finally VirtualStringTree1.EndUpdate; end; end; procedure TForm103.VirtualStringTree1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); begin VirtualStringTree1.GetNodeData<TTest>(Node).Free; end; procedure TForm103.VirtualStringTree1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); begin CellText := VirtualStringTree1.GetNodeData<TTest>(Node).TestProperty; end; { TTest } constructor TTest.Create(const AValue: string); begin FTestProperty := AValue; end; |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ich habe mein Record jetzt mal auf Class umgestellt...
Delphi-Quellcode:
Es hat tatsächlich einen Geschwindigkeitsvorteil gebracht. Mein kompletter Prozess dauert nun in etwa je nach Laune des Rechners 3,0 bis 3,2 Sekunden.
TreeData := TTreeData.Create;
TreeData.iIndex := ... TreeData.einString := ... Ich füge der VST 100000 Einträge hinzu aber es passiert noch viel viel mehr im Hintergrund. Ich denke die 3 Sekunden sind also OK. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
3 Sekunden für 100.000 Nodes sind doch noch sehr lange finde ich. Es kommt natürlich auch darauf an, wo du deine Informationen zum Füllen der Klasseninstanzen herbekommst.
Ich würde dir aber empfehlen, dass über RootNodeCount zu machen. Dann werden nämlich nur die Nodes initialisiert die aktuell angezeigt werden. Alle Children bspw. erst dann, wenn du sie aufklappst. Wenn du dazu noch ein Beispiel brauchst, dann sag bescheid. Dann schreib ich dir schnell eins oder schaue ob ich noch irgendwo eins finde. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ich finde die 3 Sekunden eigentlich OK. Wie gesagt wird noch verdammt viel zeitgleich gemacht (Dateivergleiche usw) - wirklich sehr viel =)
Das mit dem RootNodeCount verstehe ich noch nicht genau. Wenn ich RootNodeCount := XYZ mache (XYZ = die Anzahl meiner Daten), dann sehe ich in meiner VST alles doppelt und die ersten XYZ sind leer. Deine Art die Nodes freizugeben funktioniert bei mir nicht. Ich mache es immer so
Delphi-Quellcode:
Nun meckert der Compiler, dass der Ausdruck kein Initialize/Finalize benötigt.
var
Data: PTreeData; begin Data := VST.GetNodeData(Node); Finalize(Data^); |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Wenn du RootNodeCount setzt, dann wird das vst.AddChild() überflüssig. Vorher solltest du natürlich (wie auch bei AddChild()) vst.Clear aufrufen. Der Code den du dann in deiner Funktion ausführst die AddChild aufruft wird dann in das OnInitNode Event verlagert. Dort wird dann pro Node die entsprechende NodeData gesetzt. Habe aktuell kein Beispiel zur Hand, werde dir aber morgen früh eins zusammenbauen wenn es so lange Zeit hat.
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ok jetzt verstehe ich auch was du damit meintest, dass der Node nur geladen wird wenn er angezeigt wird.
Ich glaube ich warte besser auf dein Beispiel, bevor ich mir alles verhuntze :( Letzte Frage für heute: wie gebe ich die Nodes denn wieder frei, wenn er bei Finalize meckert? Mein Problem ist folgendes... der Speicherverbrauch meiner Anwendung liegt beim Start bei 11 MB. Nachdem die VST gefüllt ist bei 70 MB. Wenn ich das Formular mit der VST schließe bleibt alles bei 70 MB. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Delphi-Quellcode:
verwendet, aber die Methode mit dem nachträglichen Initialisieren klingt interessant.
AddChild
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Der Punkt bei der späteren Initialisierung ist, dass du aus dem Index eines Knotens die dazu gehörenden Daten herausfinden können musst.
Dafür brauchst du in der Regel eine dahinterliegende Datenstruktur, aus der du die Daten dann holen kannst. Die Frage ist wie viel Zeit du brauchst um diese Datenstruktur zu initialisieren. Wenn das sehr schnell geht, ist der Weg in der Tat gut machbar. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Wird das Formular nur geschlossen oder auch freigegeben? |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Das Formular mit dem VST wird nur geschlossen.
Generelle Frage: ist es normal, dass der TaskManager den Speicherverbrauch der Anwendung, wenn ich das VST-Formular schließe, nicht senkt und bei jedem Ausführen meiner Methode immer nur erhöht?
Delphi-Quellcode:
kann ich leider nicht ausführen. Ich glaube mein Delphi (XE3) ist zu alt.
VST.GetNodeData<TTreeData>(Node).Free;
Der Fehler lautet nicht genügende Parameter und dass Free unbekannt sei. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Dein Delphi ist nicht zu alt, aber deine VST Version vermutlich. Hast du die neu aus dem Repository ausgecheckt? (Das würde ich sehr empfehlen.)
Alternativ kannst du natürlich auch die nicht-generische Version von GetNodeData benutzen und auf die Klasse casten um Free aufzurufen. Zitat:
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Du machst ja scheinbar jetzt folgendes:
Delphi-Quellcode:
Da du in dem Beispiel oben (das jeanicke im übrigen auch so nur mit Generics gezeigt hat) ein Objekt instanziiert hast, musst du das dann auch wieder freigeben.
procedure TForm1.LoadNodes();
var NodeData: PNodeData; Node: PVirtualNode; begin Node := vst.AddChild(nil); NodeData := vst.GetNodeData(Node); NodeData^ := TNodeData.Create(); // Hier führst du einen Konstruktor einer Klasse aus end; Also erstellt du dir einen EventHandler für das OnFreeNode Event des VST.
Delphi-Quellcode:
procedure TForm1.vstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var NodeData: PNodeData; begin NodeData := vst.GetNodeData(Node); NodeData^.Free; end; Zitat:
Es ist etwas umständlicher zu programmieren, aber es zahlt sich bei der Geschwindigkeit und auch bei der Speicherauslastung aus. Besonders wenn man sehr viele Nodes hat die Children besitzen. Dann brauchst man bspw. die Children erst zu laden wenn der User explizit die Node aufklappen will. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
moin :)
Wie die Kollegen vorher schon anmerkten, ist die Variante mit RootNodeCount die schneller, da von vornherein die Anzahl fest steht und die ganze Initialisierung des Trees in einem Rutsch geht. Als Beispiel kannst du dir da auch mal das SpeedDemo im Demo-Ordner von VST anguggen. Das Zeit-Problem hat meistens seine Ursache im Sammeln der Daten, die angzeigt werden sollen. Ich hatte z.B. mal eine Art Mini-Explorer gebaut und dabei den Fehler gemacht, die gesamte Verzeichnisstruktur der Platte auf einen Schlag zu ermitteln. Ergebnis war, das das Initialisieren des Trees sehr lange dauerte. Was mir etwas komisch vorkommt ist, das eine Klasse schneller sein soll, als ein reiner Zeiger auf die Daten. Die Initalisierung einer Instanz sollte doch ein bischen mehr tun, als eine Zuweisung der Werte im Speicher. Werd das mal austesten. oder hat jemand eine Erklärung dafür ? :) |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Delphi-Quellcode:
und freigeben
procedure AddVSTStructure(aVST: TVirtualStringTree; aRecord: TTreeData);
var Data: PTreeData; Node: PVirtualNode; begin Node := aVST.AddChild(nil); Node.CheckType := ctCheckBox; Node.CheckState := csCheckedNormal; Data := aVST.GetNodeData(Node); Data^ := aRecord; end;
Delphi-Quellcode:
Ich werde mir später mal das neue VST runterladen und prüfen. Aber mit meiner aktuellen Version zeigt der Taskmanager nie "weniger" an.
procedure TForm2.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var Data: PTreeData; begin Data := VST.GetNodeData(Node); Data^.Free; end; Ich habe übrigens Version 5.3.0: (04 Jan 2014) sehe ich gerade. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Fang doch erstmal klein an. Setze 10 Knoten in Deinen Baum und gib die ordentlich wieder frei. Das kannst Du mit Breakpoints und ggf. sogar mittels Einzelschritt präzise nachverfolgen. Bevor Dein Code nicht im Kleinen funktioniert, brauchst Du Dir um die große Lösung nur wenig Gedanken machen. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Löschst du denn auch die Nodes mit vst.Clear(). Ansonsten kann auch nichts freigegeben werden. Setz doch mal einen Breakpoint auf die erste Zeile in deinem OnFree Event. Hält der Debugger dort überhaupt an?
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Liste der Anhänge anzeigen (Anzahl: 1)
So..hab mal ein kleines Test-Prog gebaut (Turbo Delphi !). Das sagt mir was gaaanz anderes als
jaenicke gesagt hat, bzgl. Klassen. Ich häng das mal an, evtl. kannst du dir da was abuggen. Aber wie Daniel bereits sagte, erstmal mit kleinen Datenmengen anfangen. Läßt sich leichter nachvollziehen. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo zusammen,
ich habe mal ein kleines Beispiel zusammengestellt das Wahlweise 100.000 oder auch 1.000.000 Objekte und dementsprechend genauso viele Nodes erzeugt. Zusätzlich wird das ganze noch minimalistisch mit GetTickCount protokolliert damit man mal eine grobe Vorstellung hat wie lange so etwas dauert. Ich hoffe das Beispiel hilft dir/euch beim besseren Verwalten eurer Nodes und trägt zum Beschleunigen eures Programms bei. Ich habe 2 Varianten erstellt die per Compilerschalter gewählt werden können. Einmal wird im NodeData nur der Index zum Object in der ObjectList hinterlegt und beim anderen Beispiel wir direkt der Pointer zum Object übergeben. Da kann dann jeder für sich entscheiden was ihm/ihr besser gefällt. Der Code wurde dadurch zwar etwas unübersichtlicher, aber ich denke es wird trotzdem deutlich wie es funktioniert. Wenn Ihr Fragen dazu habt, dann stellt sie. Angehängt das Testprojekt. Im Release Ordner ist auch schon eine fertige Exe damit ihr das theoretisch direkt mal ausprobieren könnt. Die aktuelle Exe wurde mit dem Compilerschalter erstellt der bewirkt, dass nur der Index aus der ObjectList im NodeData hinterlegt wird. Was schlussendlich für euch besser ist müsst ihr selbst entscheiden. Das FreeNode Event fällt durch die Verwendung der ObjectList raus, da diese die Objecte (wenn OwnsObjects auf True steht) selbst verwaltet. EDIT: Mir ist gerade aufgefallen, dass ich vergessen habe das OnGetNodeDataSize Event einzubauen. In diesem Fall ist es allerdings nicht schlimm, da ein Cardinal und ein Zeiger auf ein Objekt soweit ich weiß 4 Byte belegen. Das ist auch die Standardeinstellung des VST. Wer es dennoch einbauen möchte der kann folgendes schreiben:
Delphi-Quellcode:
Und dann natürlich noch das Event mit dem Tree verknüpfen.
procedure TForm1.vst1GetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
begin {$IFDEF WITHCARDINAL} NodeDataSize := SizeOf(Cardinal); {$ELSE} NodeDataSize := SizeOf(TMyDataClass); {$ENDIF} end; |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Nur es hat sich für mich so angehört, dass der Speicherverbrauch bei der Benutzung nicht sinkt wenn er Nodes löscht oder eine neue Ansicht laden will. Eventuell hat er ja auch das Event falsch implementiert oder ist mit seinen Klassen durcheinander gekommen. Edit: Außerdem wenn er den Speicherverlauf/Speicherverbrauch während der Ausführung beobachten will, dann sollte er die Nodes manuell mit vst.Clear() löschen. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ich habe nun folgendes gemacht.
- ich füg lediglich 10 Nodes hinzu - im FreeNode-Event ist ein Breakpoint an erster Stelle nach begin - im FormClose steht VST.Clear; Am Breakpoint wird nicht angehalten. Wenn ich da Showmessage('Free'); renischreibe, bekomme ich das aber 10x angezeigt. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Aber hast du auch die Build Konfiguration auf Debug und nicht auf Release stehen? Wie wird die Zeile/der Breakpoint nach dem Compilieren angezeigt? Ist er blau oder grün? Blau bedeutet, dass er angesprungen wird (sofern keine Bedingung im BreakPoint hinterlegt ist). Grün heißt, dass er aus welchen Gründen auch immer (häufig die Build Konfiguration) nicht anhält weil keine Debug Infos mit einkompiliert wurden. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Delphi XE3 und Release.
NodeFree wird angesprungen, das sehe ich ja an der Showmessage. Irgendetwas stimmt aber bei mir generell nicht. Nicht einmal folgende Zeile lässt sich compilieren, da TObjectList<> angeblich ein undeklarierter Bezeichner ist (Contnrs steht in den uses)
Delphi-Quellcode:
Habe daraus, hoffe es ist nicht falsch, jetzt mal = TObjectList; gemacht.
TMyDataClasses = TObjectList<TMyDataClass>;
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
TObjectList<T> steht nicht in Contnrs, sondern in Generics.Collections.
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Delphi-Quellcode:
eine reine
TObjectList<TMyDataClass>
Delphi-Quellcode:
machst ist das zwar nicht direkt falsch, aber du musst dann an jeder Stelle auf das passende Objekt casten. Durch die Generics hast du eben den Vorteil, dass du direkt die Elemente vom richtigen Typ zurück bekommst.
TObjectList
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Aviator, ich glaube ich bleibe lieber bei meiner standard-Variante. Ich bekomme deine Version nicht zum Laufen.
Im VSTGetText steht einzig und allein
Delphi-Quellcode:
Das führt zu einer Zugriffsverletzung.
var
Data: PTreeData; begin Data := VST.GetNodeData(Node); case Column of 0: ShowMessage(Data^.sFileName); end; Auf die ObjectList kann ich auch nicht zugreifen, da er dann meckert dass Integer und TreeData nicht zusammenpassen. Mit meiner Standard-Methode müsste aber doch eigentlich auch der Speicher freigegeben werden. NodeFree wird doch aufgerufe, ich verstehe das nicht. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Liste der Anhänge anzeigen (Anzahl: 1)
Ich sehe gerade, dass ich das Projekt im Release Build hochgeladen habe. Habe die Buildkonfiguration nicht umgestellt. Daher funktionieren wohl auch die Breakpoints nicht (wie ich bereits in einem der vorherigen Beiträge erwähnt hatte).
Stell mal die Konfiguration um indem du in der Projektverwaltung die Build-Konfiguration öffnest und dann doppelt auf Debug klickst. Siehe Bild im Anhang. Wenn Sie aktiv ist, dann wird sie fett markiert. Zitat:
Wenn die funktioniert, dann poste mal deine komplette Unit in der du den VST verwendest. Ich glaube das wäre dann einfacher wenn wir hier zusammen mal drüber schauen. Generics sollten kein Problem machen, da die auch in XE3 schon existierten. Ich kompiliere mal parallel noch mit XE3. Die Version habe ich zufällig gerade zur Hand. Ich schaue mal, ob das bei mir fehlerfrei funktioniert. Wenn nicht, dann suche ich den Fehler bei mir und berichte. EDIT: Also mit XE3 lässt sich mein Projekt so wie ich es hochgeladen habe problemlos kompilieren. Funktioniert das denn bei dir? Wenn das funktioniert, dann können wir zum nächsten Schritt gehen der dann wäre, dass du uns die Fehlermeldungen und den SourceCode postest. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ich kann es zwar jetzt kompilieren aber ich verstehe noch immer etwas nicht.
Einmal steht in GetText:
Delphi-Quellcode:
Und ein anderes mal in InitChildren:
{$IFDEF WITHCARDINAL}
CellText := FMyDataClasses[NodeData^].Name; {$ELSE} CellText := NodeData^.Name; {$ENDIF}
Delphi-Quellcode:
WITHCARDINAL ist also vertauscht. Was ist das richtige?
{$IFDEF WITHCARDINAL}
NodeData^ := Node^.Index; {$ELSE} NodeData^ := FMyDataClasses[Node^.Index]; {$ENDIF} Ich bin wieder zu meiner alten Version umgestiegen und gucke mal wie ich deine bei mir einbauen kann. Ich verstehe einfach nicht, wieso der Speicher nicht freigegeben wird OBWOHL er in FreeNode einsteigt. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
vertauscht ist da nichts. Das ist schon alles richtig so. In der Version WITHCARDINAL habe ich in NodeData^ nur den Index des Objektes in der TObjectList. Folglich muss ich bei GetText auf das Object in der TObjectList mit dem Index NodeData^ zugreifen. Ich hatte mit den Compilerschaltern nur zeigen wollen, dass man entweder mit einem Index ODER mit einem (Zeiger auf ein) Objekt arbeiten kann. Das war jetzt vielleicht etwas verwirrend. Am besten suchst du dir eine Variante aus und löschst dann alles was nicht dazu gehört. Dann wird aus dem oben gezeigten SourceCode bspw. folgendes: Ich bleibe jetzt mal bei der Variante mit dem Object. Die ist nachher an allen anderen Stellen im SourceCode wesentlich übersichtlicher.
Delphi-Quellcode:
Im Init wird einmal das Objekt zugewiesen und nachher wird mit Hilfe von
procedure TForm1.vst1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string); var NodeData: PMyDataClass; begin if (vst1.GetNodeLevel(Node) = 0) then begin NodeData := vst1.GetNodeData(Node); CellText := NodeData^.Name; end else CellText := 'SubItem ' + IntToStr(Node^.Index + 1); end; procedure TForm1.vst1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); var NodeData: PMyDataClass; begin NodeData := vst1.GetNodeData(Node); NodeData^ := FMyDataClasses[Node^.Index]; if (vst1.GetNodeLevel(Node) = 0) then begin // Nur auf dem ersten NodeLevel Children zulassen if (NodeData^.HasChildren) then begin Include(InitialStates, ivsHasChildren); // Hier wird im Status der Node vermerkt, dass die Node mindestens 1 ChildNode hat und das + Symbol angezeigt werden soll end; end; end;
Delphi-Quellcode:
immer wieder direkt darauf zugegriffen. Ich hoffe das hier macht es etwas übersichtlicher. Wenn nicht, dann frag nochmal nach. Ich helfe dir gerne. Stand anfangs vor dem selben Problem und hatte mich immer ein Stückchen weiter vorgearbeitet.
NodeData^
|
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Danke für deine Geduld, jetzt funktioniert es nachdem ich mich noch einmal in Ruhe hingesetzt habe. Wo vorher der Fehler war, weiß ich nicht aber ich denke es war ein ungücklicher Tippfehler.
Ich habe nun folgendes beobachtet. Der speicher meiner Anwendung geht von 11 MB auf 49 MB hoch, wenn ich meine ListView mit 100000 Einträgen fülle. Ein anschließendes freigeben der ObjectList (schließen des Formulars, Ende der Routine) lässt den Speicher auf 28 MB sinken. Bei 10000 Dateien geht der Speicherverbrauch von 11 MB hoch auf 14 MB und beim Ende der Routine geht der Speicher -nicht- runter. Ich denke mir, die Anwendung behält sich da etwas im Speicher oder ähnliches. Dein Projekt-Beisiel: bei 100000 Einträgen geht der Speicher von 3 MB hoch auf 23 MB. Beim Freigeben der ObjectList sinkt der speicherverbrauch auf 11 MB. Auch hier behält sich die Anwendung (Laienwissen) eventuell etwas im Speicher? Also alles OK? |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ich würde mal sagen ja. Bei einer anderen Anwendung bei der ich sehr viele Daten aus einer SQLite Datenbank lade habe ich den Effekt zwar nicht, aber solange alles freigegeben wird, ist da alles in Ordnung.
Zur Kontrolle kannst du in deiner DPR Datei mal die Zeile
Delphi-Quellcode:
einfügen. Dann erhälst du nach dem Beenden deines Programms ein Fenster in der MemoryLeaks aufgelistet werden, wenn denn überhaupt welche vorhanden sind.
ReportMemoryLeaksOnShutdown := True;
Funktioniert dein Programm denn jetzt mit InitNode so wie in meinem Beispiel? Oder hakt es noch irgendwo. Dein erster Satz klingt sehr positiv, daher würde ich mal davon ausgehen das alles funktioniert. Aber eine Kontrolle schadet ja nie. :-D |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Den präzisen Speicherverbrauch einer Anwendung zu messen ist nicht trivial. Der Taskmanager ist hierfür kein besonders gutes Werkzeug, da er nur einen groben Wert widerspiegelt. Es ist bei der Speicherverwaltung von Windows (und auch anderen Betriebssystemen) durchaus möglich, dass ein Speicherbereich intern als "frei" gekennzeichnet wird, dem Prozess aber weiterhin zugeordnet wird, da die Wahrscheinlichkeit, dass dieser wieder Speicher brauchen wird i.A. recht hoch ist.
Du kämpfst an vielen Fronten gleichzeitig. Baue Dir ein kleines Beispiel und mache Dir daran die Speicherverwaltung des TreeViews klar - dann übertrage das auf andere Lösungen. Lasse Dich aber nicht von Seiteneffekten wie der Speicheranzeige des Taskmanagers verwirren. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
@Aviator ja es funktioniert jetzt.
Nur was mir jetzt erst aufgefallen ist > meine CheckBoxen im VirtualStringTree sind verschwunden. Ich weiß gerade nicht ob es am Update von VST liegt oder nicht. Muss ich prüfen. Daniel: das habe ich zum Glück bereits gemacht. Ich habe alles was das VST angeht aus dem Projekt kopiert und in eine saubere kleine Spiele-Wiese-Anwendung gepackt. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Zitat:
Möglicherweise wurde seit deiner letzten Version in den TreeOptions etwas verändert und du musst noch einen zusätzlichen Haken setzen. Ich gehe mal davon aus, dass du die Checkboxen vor den Nodes meinst mit denen du diese auswählen kannst. |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Ein VirtualStringTree hat doch einen Support für Checkboxen, wusstest du das nicht?
Edit: verdammt, die CheckBoxen sind auch mit der alten Version von VST nicht mehr da. Muss wahrscheinlich an was anderem liegen :( Edit 2: ein bisschen Nachdenken hätte nicht geschadet! Die Knoten werden ja jetzt erst bie der Anzeige initialisiert wenn ich das richtig verstanden habe. Demnach musste Folgendes zusätzlich in InitNode
Delphi-Quellcode:
procedure TForm2.VSTInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var Data: PMyDataClass; begin Data := VST.GetNodeData(Node); // .... dem VST natürlich auch sagen, dass er die verflicksten Dinger anzeigen soll! Node.CheckType := ctCheckBox; Node.CheckState := csCheckedNormal; Data^ := FMyDataClasses[Node^.Index]; end; |
AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
Zitat:
Ohne mich jetzt größer darzustellen als ich bin, aber ich glaube es gibt keine Funktion des VST die ich nicht kenne. Ich arbeite mittlerweile schon seit einigen Jahren mit der Komponente und habe schon sehr viele Werke damit vollbracht. :-D Und ja: Mit dem setzen des CheckTypes und des CheckStates liegst du richtig. Das musst du jetzt (wie vorher auch) jeder Node einzeln zuordnen. Ich dachte nur (siehe meinen letzten Beitrag), dass du eventuell den CheckSupport in den TreeOptions nicht eingeschaltet hattest oder sogar eine neue Einstellung hinzugekommen ist seit deiner letzten Version. Weil dann wird nämlich auch nix angezeigt. Aber du hast es ja jetzt gefunden. :thumb: Happy :coder: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23: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