Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Nodes einer VirtualStringTree hinzufügen - aber schneller! (https://www.delphipraxis.net/190454-nodes-einer-virtualstringtree-hinzufuegen-aber-schneller.html)

Jim Carrey 5. Okt 2016 17:44

Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Ich füge aktuell einer VirtualStringTree einiges An Einträgen hinzu.
Ungefähr so
Delphi-Quellcode:
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;
Mein Record ist ein ganz normales Record
Delphi-Quellcode:
type
 PTreeData = ^TTreeData;

 TTreeData = record
  iIndex: Integer;
  // Hier stehen ein paar Variablen.. Strings, Boolean etc
 end;
Das Hinzufügen dauert komischerweise recht lange, obwohl VirtualStringTree1.BeginUpdate und VirtualStringTree1.EndUpdate schon gesetzt sind.
Ist das normal, dass das bei 100000 Einträgen und mehr in etwa 10 Sekunden dauert?

Aviator 5. Okt 2016 17:51

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:
OnInitNode()
und
Delphi-Quellcode:
OnInitChildren()
. Beispiele kann ich aktuell nicht machen. Erst so in 2 Stunden wieder.

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.

Jim Carrey 5. Okt 2016 17:58

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!

jaenicke 5. Okt 2016 20:45

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:
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;
NodeCount für den Knoten setzen und später initialisieren geht natürlich noch schneller, ist aber meist auch etwas aufwendiger.

Jim Carrey 5. Okt 2016 22:13

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Ich habe mein Record jetzt mal auf Class umgestellt...
Delphi-Quellcode:
TreeData := TTreeData.Create;
TreeData.iIndex := ...
TreeData.einString := ...
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.
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.

Aviator 5. Okt 2016 22:20

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.

Jim Carrey 5. Okt 2016 22:31

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:
var
 Data: PTreeData;
begin
 Data := VST.GetNodeData(Node);
 Finalize(Data^);
Nun meckert der Compiler, dass der Ausdruck kein Initialize/Finalize benötigt.

Aviator 5. Okt 2016 22:35

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.

Jim Carrey 5. Okt 2016 22:38

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.

Zacherl 5. Okt 2016 22:57

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Aviator (Beitrag 1349905)
Wenn du dazu noch ein Beispiel brauchst, dann sag bescheid. Dann schreib ich dir schnell eins oder schaue ob ich noch irgendwo eins finde.

Mich würde das auf jeden Fall interessieren :stupid: Habe bisher nie mit so riesigen Datenmengen gearbeitet und deshalb immer nur
Delphi-Quellcode:
AddChild
verwendet, aber die Methode mit dem nachträglichen Initialisieren klingt interessant.

jaenicke 5. Okt 2016 23:01

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.

jaenicke 5. Okt 2016 23:03

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Jim Carrey (Beitrag 1349909)
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.

Bei Klassen? Das ist in meinem Beispiel ja dabei.
Wird das Formular nur geschlossen oder auch freigegeben?

Jim Carrey 5. Okt 2016 23:04

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:
VST.GetNodeData<TTreeData>(Node).Free;
kann ich leider nicht ausführen. Ich glaube mein Delphi (XE3) ist zu alt.
Der Fehler lautet nicht genügende Parameter und dass Free unbekannt sei.

jaenicke 5. Okt 2016 23:13

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:

Zitat von Jim Carrey (Beitrag 1349913)
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?

Wenn du Klassen nutzt und diese nur erstellst und nicht freigibst, ja.

Aviator 5. Okt 2016 23:15

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Du machst ja scheinbar jetzt folgendes:

Delphi-Quellcode:
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;
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.

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:

Zitat von Zacherl (Beitrag 1349910)
Zitat:

Zitat von Aviator (Beitrag 1349905)
Wenn du dazu noch ein Beispiel brauchst, dann sag bescheid. Dann schreib ich dir schnell eins oder schaue ob ich noch irgendwo eins finde.

Mich würde das auf jeden Fall interessieren :stupid: Habe bisher nie mit so riesigen Datenmengen gearbeitet und deshalb immer nur
Delphi-Quellcode:
AddChild
verwendet, aber die Methode mit dem nachträglichen Initialisieren klingt interessant.

Ich werde mal so ein Beispiel aufbauen. Aber wie jeanicke es ebenfalls schon erwähnt hat, brauchst du eine entsprechende Datenstruktur aus der du dir die Daten dann beim Initialisieren ziehen kannst. Sei es eine Query oder eine eigene Klassenstruktur wo Objekte bspw. in einer ObjectList abgelegt sind.

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.

Ghostwalker 6. Okt 2016 05:55

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 ? :)

Aviator 6. Okt 2016 07:31

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Ghostwalker (Beitrag 1349922)
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 ? :)

Lies dir mal Beitrag #4 durch. Dort erklärt jaenicke wieso das so ist. :stupid:

Jim Carrey 6. Okt 2016 08:35

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Aviator (Beitrag 1349918)
Du machst ja scheinbar jetzt folgendes:

Delphi-Quellcode:
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;
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.

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;

Nicht ganz ich mache es so (da steht Record aber es ist eine Class, keine Sorge!)
Delphi-Quellcode:
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;
und freigeben
Delphi-Quellcode:
procedure TForm2.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
 Data: PTreeData;
begin
 Data := VST.GetNodeData(Node);
 Data^.Free;
end;
Ich werde mir später mal das neue VST runterladen und prüfen. Aber mit meiner aktuellen Version zeigt der Taskmanager nie "weniger" an.
Ich habe übrigens Version 5.3.0: (04 Jan 2014) sehe ich gerade.

Daniel 6. Okt 2016 08:55

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Jim Carrey (Beitrag 1349913)
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?

Das ist genau dann "normal", wenn man ein Speicherloch hat.
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.

Aviator 6. Okt 2016 08:56

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?

Ghostwalker 6. Okt 2016 09:40

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.

Aviator 6. Okt 2016 09:41

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:
procedure TForm1.vst1GetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
begin
  {$IFDEF WITHCARDINAL}
  NodeDataSize := SizeOf(Cardinal);
  {$ELSE}
  NodeDataSize := SizeOf(TMyDataClass);
  {$ENDIF}
end;
Und dann natürlich noch das Event mit dem Tree verknüpfen.

jaenicke 6. Okt 2016 11:13

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Aviator (Beitrag 1349942)
Löschst du denn auch die Nodes mit vst.Clear(). Ansonsten kann auch nichts freigegeben werden.

Das stimmt nicht, zumindest nicht mit der aktuellsten Version (mit der ich es getestet hatte). Bei der Freigabe der Tree wurde auch OnFreeNode aufgerufen.

Aviator 6. Okt 2016 11:38

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von jaenicke (Beitrag 1349971)
Zitat:

Zitat von Aviator (Beitrag 1349942)
Löschst du denn auch die Nodes mit vst.Clear(). Ansonsten kann auch nichts freigegeben werden.

Das stimmt nicht, zumindest nicht mit der aktuellsten Version (mit der ich es getestet hatte). Bei der Freigabe der Tree wurde auch OnFreeNode aufgerufen.

Ja natürlich werden dann auch die Nodes gelöscht wenn der Tree freigegeben wird, das ist ja klar. Das wäre ja sonst ein Fehler in der VirtualTreeView Komponente. :shock:

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.

Jim Carrey 6. Okt 2016 11:50

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.

Aviator 6. Okt 2016 11:55

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Jim Carrey (Beitrag 1349975)
Am Breakpoint wird nicht angehalten.

Weiß jetzt leider nicht welche Delphi Version du hast. Könntest du bei Gelegenheit mal in deinem Profil hinterlegen.

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.

Jim Carrey 6. Okt 2016 11:59

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:
TMyDataClasses = TObjectList<TMyDataClass>;
Habe daraus, hoffe es ist nicht falsch, jetzt mal = TObjectList; gemacht.

DeddyH 6. Okt 2016 12:09

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
TObjectList<T> steht nicht in Contnrs, sondern in Generics.Collections.

Aviator 6. Okt 2016 12:40

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Jim Carrey (Beitrag 1349977)
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:
TMyDataClasses = TObjectList<TMyDataClass>;
Habe daraus, hoffe es ist nicht falsch, jetzt mal = TObjectList; gemacht.

Wie DeddyH schon sagt ist TObjectList<T> in System.Generics.Collections deklariert. Wenn du aus
Delphi-Quellcode:
TObjectList<TMyDataClass>
eine reine
Delphi-Quellcode:
TObjectList
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.

Jim Carrey 6. Okt 2016 12:42

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:
var
 Data: PTreeData;
begin
 Data := VST.GetNodeData(Node);

 case Column of
  0: ShowMessage(Data^.sFileName);
 end;
Das führt zu einer Zugriffsverletzung.
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.

Aviator 6. Okt 2016 12:54

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:

Zitat von Jim Carrey (Beitrag 1349981)
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:
var
 Data: PTreeData;
begin
 Data := VST.GetNodeData(Node);

 case Column of
  0: ShowMessage(Data^.sFileName);
 end;
Das führt zu einer Zugriffsverletzung.
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.

Nicht so schnell aufgeben. Das ist als Programmierer sehr schlecht. Wenn du meine Version kompilierst, bekommst du dann irgendwelche Fehlermeldungen? Wenn ja, welche? Kopier die mal und poste die hier.

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.

Jim Carrey 6. Okt 2016 13:16

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:
{$IFDEF WITHCARDINAL}
   CellText := FMyDataClasses[NodeData^].Name;
{$ELSE}
   CellText := NodeData^.Name;
{$ENDIF}
Und ein anderes mal in InitChildren:
Delphi-Quellcode:
{$IFDEF WITHCARDINAL}
 NodeData^ := Node^.Index;
{$ELSE}
 NodeData^ := FMyDataClasses[Node^.Index];
{$ENDIF}
WITHCARDINAL ist also vertauscht. Was ist das richtige?
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.

Aviator 6. Okt 2016 13:32

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Jim Carrey (Beitrag 1349988)
Ich kann es zwar jetzt kompilieren aber ich verstehe noch immer etwas nicht.

Einmal steht in GetText:
Delphi-Quellcode:
{$IFDEF WITHCARDINAL}
   CellText := FMyDataClasses[NodeData^].Name;
{$ELSE}
   CellText := NodeData^.Name;
{$ENDIF}
Und ein anderes mal in InitChildren:
Delphi-Quellcode:
{$IFDEF WITHCARDINAL}
 NodeData^ := Node^.Index;
{$ELSE}
 NodeData^ := FMyDataClasses[Node^.Index];
{$ENDIF}
WITHCARDINAL ist also vertauscht. Was ist das richtige?

Hallo Jim,

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:
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;
Im Init wird einmal das Objekt zugewiesen und nachher wird mit Hilfe von
Delphi-Quellcode:
NodeData^
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.

Jim Carrey 6. Okt 2016 14:06

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?

Aviator 6. Okt 2016 14:17

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:
ReportMemoryLeaksOnShutdown := True;
einfügen. Dann erhälst du nach dem Beenden deines Programms ein Fenster in der MemoryLeaks aufgelistet werden, wenn denn überhaupt welche vorhanden sind.

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

Daniel 6. Okt 2016 14:26

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.

Jim Carrey 6. Okt 2016 14:38

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.

Aviator 6. Okt 2016 14:48

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Jim Carrey (Beitrag 1350002)
@Aviator ja es funktioniert jetzt.

Super! :thumb:
Zitat:

Zitat von Jim Carrey (Beitrag 1350002)
meine CheckBoxen im VirtualStringTree sind verschwunden.

Welche Checkboxen? :shock:

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.

Jim Carrey 6. Okt 2016 14:49

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;

Aviator 6. Okt 2016 15:09

AW: Nodes einer VirtualStringTree hinzufügen - aber schneller!
 
Zitat:

Zitat von Jim Carrey (Beitrag 1350005)
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;

Doch klar wusste ich das. :lol:
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 00:06 Uhr.
Seite 1 von 2  1 2      

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