Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   VirtualStringTree und Klasseninstanzen - Node Data finden (https://www.delphipraxis.net/196029-virtualstringtree-und-klasseninstanzen-node-data-finden.html)

günni0 16. Apr 2018 23:22


VirtualStringTree und Klasseninstanzen - Node Data finden
 
Ich versuche mir gerade eine Funktion zu schreiben die mir die Node-Daten anhand eines Index findet

Delphi-Quellcode:
function GetNodeData(Index: Integer): TUserdata;
var
 i: Integer;
begin
 Result := nil;
 for i := 0 to _UserDataClasses.Count - 1 do
  if _UserDataClasses[i].Index = Index then
   begin
    Result := _UserDataClasses[i].aNode.GetData<TUserData>;
    Exit;
   end;
end;
Mein Problem besteht darin, dass ich nicht weiß ob ich mich am Index .Index oder [i] orientieren muss, um das zurückzugeben was ich suche.

In einer anderen Prozedur füge ich Klasseninstanzen in meine ObjectList hinzu und dachte, dass Folgendes funktioniert
Delphi-Quellcode:
if InsertAtPosition > -1 then
 _UserDataClasses.Insert(InsertAtPosition, _UserData)
else
 _UserDataClasses.Add(_UserData);
Das .Insert( funktioniert leider überhaupt nicht wie gewollt. Das VST zeichnet mir den an beispielsweise Index 2 hinzugefügten Eintrag gar nicht und kopiert irgendwie nur den aller letzten.

Daher die Frage.
Ist es vollkommen egal in welcher Reihenfolge die Daten in der ObjectList liegen [man sortiert das VST ja glaube ich eh manuell] und soll man sich nur am Index .Index (eigene Variable in der Klasse) orientieren den ich dann jetzt so setze
Delphi-Quellcode:
// Prozedur die Daten lädt, eine Klasseninstanz erstellt und in die ObjectList packt. Mit dem optionalen Parameter UseIndex kann man den Inhalt der Variablen Index selber bestimmen.
if UseIndex> -1 then
 _UserDataClasses.Index := UseIndex
else
 _UserData.Index := _UserDataClasses.Count;

_UserDataClasses.Add(_UserData);
?

zweite Frage. Wie schaffe ich es die Funktion GetNodeData(Index: Integer) oben als überladene Funktion ohne doppelten Code bereitzustellen?
Beispielsweise wenn ich als Parameter UserName: string haben und diesen auch finden möchte?
Ich könnte die Funktion einfach kopieren und statt .Index = Index dann .UserName = Username prüfen. Aber das wäre doppelter Code.


Bin für Hilfe sehr dankbar!


Oder meine frage etwas anders formuliert.
Wenn ich einen Nutzernamen finden möchte, iteriere ich dann durch die Nodes oder durch die ObjectList?
Delphi-Quellcode:
// General helper function used in multiple other functions (e.g. DeleteUserNameNode)
function FindUserIDByName(const UserName: string): Integer;
var
 i: Integer;
begin
 Result := -1;
 if Assigned(_UserDataClasses) then
  begin
   for i := 0 to _UserDataClasses.Count - 1 do
    begin
     if AnsiSameText(_UserDataClasses[i].UserName, UserName) then
      begin
       Result := i;
       Break;
      end;
    end;
  end;
end;

function FindUserIDByIndex(iIndex: Integer): PVirtualNode;
begin
 Result := _VST.GetFirst(True);
 while Assigned(Result) and (_VST.AbsoluteIndex(Result) <> Cardinal(iIndex)) do
  Result := _VST.GetNext(Result, True);
end;

procedure DeleteUserNameNode(const UserName: string);
var
 Node: PVirtualNode;
begin
 DeleteUserNameNode(FindUserIDByName(UserName));
end;

procedure DeleteUserNameNode(iIndex: Integer);
var
 Node: PVirtualNode;
begin
 Node := FindUserNameByIndex(iIndex);
 if Assigned(Node) then
  _VST.DeleteNode(Node);
end;
Irgendwie bin ich gerade total durcheinander weil ich absolut keine Ahnung habe, an welche Daten ich mich jetzt halten soll... Klasseninstanzen oder nicht?
Bei FindUserIDByName(<string>) halte ich mich ganz klar daran den Nutzer anhand des Namens zu finden und durchsuche die Klasseninstanzen.
Bei FindUserNameByIndex(<int>) durchsuche ich aber direkt das Index der VST und greife nicht auf die Klasseninstanzen zu. Da ist doch schon der erste Fehler oder?

TiGü 17. Apr 2018 08:21

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Warum so kompliziert?
Bei allen wichtigen Eventhandlern des VST hast du doch eine Referenz auf den Node.
Die Objektliste machste du nur aus Speicherfreigabegründen.

Delphi-Quellcode:
procedure TForm2.VirtualStringTree1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType; var CellText: string);
var
  UserData: TUserData;
begin
  if Assigned(Node) then
  begin
    UserData := Node.GetData<TUserData>;
    if Assigned(UserData) then
    begin
      case Column of
        0:
          CellText := UserData.FirstName;
        1:
          CellText := UserData.LastName;
        2:
          CellText := UserData.Address;
      end;
    end;
  end;
end;

günni0 17. Apr 2018 08:25

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Wie ich Text lade ist mir klar.

Was mir nicht klar ist, ist der letzte Abschnitt aus meinem ersten Beitrag.

Ich möchte, dass wenn ich DeleteUserNameNode(<string>) aufrufe genau dasselbe gelöscht wird wie wenn ich DeleteUserNameNode(<int>) aufrufe.

Letzteres ist aber sicher nicht gleich wie ersteres denn in FindUserIDByIndex greife ich direkt auf das VST zu und nicht wie bei allen anderen Prozeduren auf die Klasseninstanzen um an die Daten zu kommen. Ich möchte mir nur ein paar kleine Helfer-prozeduren zusammenstellen, um später doppelten Code zu vermeiden. Aber diese Basis muss auch korrekt sein, sonst geht später alles schief.


--------------- Schnipps
ich glaube ich habs. Hier meine Änderung. Nodes werden jetzt auch korrekt bei umsortierter Liste gelöscht.
Hier ein Beispiel, um Nodes (+ Daten da OwnObjects True) aus einem VST, egal wie es sortiert ist, zu löschen.

Delphi-Quellcode:
// Helferfunktion, um UserName zu finden
function FindUserIDByName(const UserName: string): Integer;
var
 i: Integer;
begin
 Result := -1;
 if Assigned(_UserDataClasses) then
  begin
   for i := 0 to _UserDataClasses.Count - 1 do
    begin
     if AnsiSameText(_UserDataClasses[i].UserName, UserName) then
      begin
       Result := i;
       Break;
      end;
    end;
  end;
end;

// Helferfunktion, um den Node im VST anhand eines gesuchten Index zurückzugeben (Achtung: nicht AbsoluteIndex, sondern der Index in meinen Klassendaten!)
function FindUserIDByIndex(iIndex: Integer): PVirtualNode;
var
 i: Integer;
begin
 Result := nil;
 for i := 0 to _UserDataClasses.Count - 1 do
  if _UserDataClasses[i].Index = iIndex then
   begin
    Result := _UserDataClasses[i].aNode;
    Break;
   end;
 // Result := _VST.GetFirst(True);
 // while Assigned(Result) and (_VST.AbsoluteIndex(Result) <> Cardinal(iIndex)) do
 //  Result := _VST.GetNext(Result, True);
end;

procedure DeleteUserNameNode(const UserName: string);
var
 Node: PVirtualNode;
begin
 DeleteUserNameNode(FindUserIDByName(UserName));
end;

procedure DeleteUserNameNode(iIndex: Integer);
var
 Node: PVirtualNode;
begin
 Node := FindUserNameByIndex(iIndex);
 if Assigned(Node) then
  _VST.DeleteNode(Node);
end;

// Aufruf
DeleteUserNameNode('Peter Wurst'); // Sucht den Namen, den Index (in den Klassendaten) und löscht den Node

DeleteUserNameNode(2); // Sucht in den Klassendaten nach einem Eintrag mit Index = 2 und löscht den dazugehörigen Node
Ob das mit dem Index nun so korrekt ist, muss ich erst noch sehen. Aber es erscheint mir logischer über die Variable Index der Klassendaten zu prüfen statt über den VST AbsoluteIndex.

TiGü 17. Apr 2018 08:49

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
In TUserData eine Referenz auf PVirtualNode zu halten ist schon von vornherein ein Designfehler.
Der VST ist nur ein Abbild von deinen Userdaten in _UserDataClasses. Alle Operationen wie hinzufügen und löschen sollten darüber geschehen und danach dann ein aktualisieren/updaten/neuzeichnen des VST.

günni0 17. Apr 2018 08:53

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Delphi-Quellcode:
 iUserNameID := FindUserNameIDByName('Peter Wurst'); // // Helferfunktion, um den Index der Klasseninstanz für den Nutzer zu finden (um doppelten Code zu vermeiden)
 if iUserNameID > -1 then
  begin
   _UserDataClasses[iUserNameID].sUserName := 'Peter Lustig';

   _VST.InvalidateNode(_UserDataClasses[iUserNameID ].aNode); //  ?
  end;
Danke für den Hinweis. Wie lade ich im obigen Beispiel denn dann einen Node neu, nachdem ich ihn geändert habe? Ohne InvalidateNode müsste ich erst die Maus über das VST bewegen, damit es neugezeichnet wird. Oder zeichnet man einfach das ganze VST mit _VST.Invalidate; neu?

Und das hier funktioniert dann ja auch nicht mehr
Delphi-Quellcode:
function FindUserIDByIndex(iIndex: Integer): PVirtualNode;
var
 i: Integer;
begin
 Result := nil;
 for i := 0 to _UserDataClasses.Count - 1 do
  if _UserDataClasses[i].Index = iIndex then
   begin
    Result := _UserDataClasses[i].aNode; // <=
    Break;
   end;
 // Result := _VST.GetFirst(True);
 // while Assigned(Result) and (_VST.AbsoluteIndex(Result) <> Cardinal(iIndex)) do
 // Result := _VST.GetNext(Result, True);
end;

TiGü 17. Apr 2018 09:05

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Das wird jetzt ineffizient in der Kommunikation.
Vorschlag: Baue ein kleines Beispielprojekt mit den wesentlichen Operationen (hinzufügen, löschen, ändern etc.) und lade es hier als Zip-Archiv hoch.
Anhand von richtigen Code kann dir besser geholfen werden.

günni0 17. Apr 2018 09:09

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Das ist nicht so einfach. Aber ich sehe schon, das ich die Referenz auf Node gar nicht weglassen kann.
Wenn ich einen Eintrag aus meiner ObjectList lösche, werden zwar die Daten gelöscht, aber nicht der dazugehörige "Node" selber im VST.

TiGü 17. Apr 2018 09:11

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Zitat:

Zitat von günni0 (Beitrag 1399475)
Das ist nicht so einfach. Aber ich sehe schon, das ich die Referenz auf Node gar nicht weglassen kann.
Wenn ich einen Eintrag aus meiner ObjectList lösche, werden zwar die Daten gelöscht, aber nicht der dazugehörige "Node" selber im VST.

Doch, das ist ganz einfach mit dem Beispielprojekt. Man muss es nur machen! Ein TUserData mit zwei Properties, ein VST und dann noch zwei, drei Buttons und ein, zwei Editfelder.

Nach aktualisieren bzw. ändern der Objekte in der Objektliste machst du einfach ein VST.Clear und neu hinzufügen.
So hast du immer einen konsistenten Stand.

günni0 17. Apr 2018 09:14

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Wenn ich VST.Clear aufrufe, lösche ich aber auch alle meine Klasseninstanzen.
Das war ja genau das was ich wollte: lösche ich einen Node, löscht er die Klasseninstanz die dranhängt direkt mit.

Immer das ganze VST löschen und neuladen war auch genau das, was ich vermeiden wollte mit den Daten die ich im Hintergrund halte.

Aviator 17. Apr 2018 09:39

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Warum löscht er deine Instanz? Das kann nur der Fall sein, wenn du OnFreeNode implementiert hast. Das solltest du nicht machen wenn deine Instanzen von der ObjectList verwaltet werden.

EDIT: Du musst natürlich auch aufpassen, dass deine Instanz so lange existiert, wie es eine Node im VST gibt die darauf zugreift. Ansonsten hagelt es AVs.

Das bedeutet im Umkehrschluss: Erst die Nodes im VST löschen, dann die Instanz aus der ObjectList werfen und die Nodes wieder erzeugen.

günni0 17. Apr 2018 09:46

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich mache gerade ein Beispiel. 10 Minuten noch.

So ganz klappt es noch nicht. Speziell wenn man erst den Button Node mit Idx 2 löschen drückt und dann Node Peter Wurst löschen.

Mein Ziel wäre es, die Referenz auf Node wegzubekommen und die Möglichkeit zu haben, das wenn ich eine Klasseninstanz lösche, auch gleich der Node mit weg ist.
Aktuell ist es ja so, dass ich den Node löschen muss. Und das geht nur mit einer Referenz da drauf. Aber ihr seht, mein Code ist wie Pasta ... nix funktioniert.

Aviator 17. Apr 2018 10:09

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Das nächste Mal bitte als Projekt ;)

Mach mal folgendes, aber bedenke, dass das jetzt nur eine Lösung für deine Vorgehensweise hier ist. Und bitte alles beachten. Ich hänge bewusst die Datei nicht an, damit du die Änderungen auch selbst einbauen musst und hoffentlich auch verstehst:

Delphi-Quellcode:
procedure TForm2.Button2Click(Sender: TObject);
begin
 VST.Clear;
 DeleteNode(2); // Daten anhand des Index löschen. 2 ist nicht der absolute Index sondern der, der in Button1Click gesetzt wird
 VST.RootNodeCount := aVSTDataClasses.Count;
end;

procedure TForm2.Button3Click(Sender: TObject);
begin
  VST.Clear;
  DeleteNode('Peter Wurst'); // Daten anhand eines Nutzernamens löschen
  VST.RootNodeCount := aVSTDataClasses.Count;
end;
Delphi-Quellcode:
procedure DeleteNode(iIndex: Integer); overload;
//var
// Node: PVirtualNode;
begin
  aVSTDataClasses.Delete(iIndex);

// Node := FindUserNodeByIndex(iIndex);
// if Assigned(Node) then
//  Form2.VST.DeleteNode(Node);
end;
Delphi-Quellcode:
procedure TForm2.FormCreate(Sender: TObject);
var
 Column: TVirtualTreeColumn;
 i: Byte;
begin
 ReportMemoryLeaksOnShutdown := True;
 
 ...

 VST.OnInitNode := VSTInitNode;
// VST.OnFreeNode := VSTFreeNode;  // <--- WICHTIG! ENTFERNEN!
 VST.OnGetText := VSTGetText;
end;

günni0 17. Apr 2018 10:18

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Ok Moment ganz langsam für meinen alten Kopf.
Heißt das jetzt, dass du mit 2, 3 Zeilen Umstellung das so gemacht hast, dass man jetzt eine Klasseninstanz löscht, das Node verschwindet (man löscht ja alle mit Clear) und alles neugezeichnet wird?
Wird das Neuzeichnen durch das Setzen von RootNodeCount ausgelöst?

Das ist dann ja genau das was TiGü meinte, nur habe ich es leider nicht ganz verstanden.

Aviator 17. Apr 2018 10:23

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Ja das ist genau das was TiGü meinte. :thumb:

Dein größter Fehler war eben (wie ich in meinem vorletzten Post schrieb), dass du das OnFreeNode Event implementiert hast. OnFreeNode gibt die Daten die an die Node gebunden sind frei. Zumindest, wenn du das in dem Event so festgelegt hast.

Und da du im OnFreeNode() die Instanz per Remove() aus der ObjectList gelöscht hast, wurde die natürlich auch beim leeren des Trees mit VST.Clear() ebenfalls gelöscht.

Das Neuzeichnen des Trees wird durch das setzen von RootNodeCount, aber auch durch das vorhergehende löschen der Nodes mit VST.Clear() ausgeführt.

günni0 17. Apr 2018 10:26

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
TiGü schriebe, dass es schlechtes Design wäre sich eine Referenz auf Node zu halten.

Ich habe eine Funktion die sieht so aus
Delphi-Quellcode:
function FindUserNodeByIndex(iIndex: Integer): PVirtualNode;
var
 i: Integer;
begin
 Result := nil;
 for i := 0 to aVSTDataClasses.Count - 1 do
  if aVSTDataClasses[i].Index = iIndex then
   begin
    Result := aVSTDataClasses[i].aNode;
    Break;
   end;
end;
Ist von sowas dann abzuraten?

Die markierte Zeile unten kann dann vermutlich auch weg
Delphi-Quellcode:
procedure TForm2.VSTInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
begin
 Node.SetData<TVSTData>(aVSTDataClasses[Node.Index]);
 aVSTDataClasses[Node.Index].aNode := Node; // ----------------------------------------------
end;
So würde ich dann beispielsweise den Text eines Properties ändern ohne die Node-Referenz
Delphi-Quellcode:
 aVSTDataClasses[5].sUserName := 'XXXXXXXXXXXXXX';

 VST.Invalidate; // InvalidateNode(aVSTDataClasses[5].aNode);

Aviator 17. Apr 2018 10:27

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Habe dein Edit leider erst nach meinem Post gesehen.

Zitat:

Zitat von günni0 (Beitrag 1399494)
TiGü schriebe, dass es schlechtes Design wäre sich eine Referenz auf Node zu halten.

ich habe eine Funktion die sieht so aus
Delphi-Quellcode:
function FindUserNodeByIndex(iIndex: Integer): PVirtualNode;
var
 i: Integer;
begin
 Result := nil;
 for i := 0 to aVSTDataClasses.Count - 1 do
  if aVSTDataClasses[i].Index = iIndex then
   begin
    Result := aVSTDataClasses[i].aNode;
    Break;
   end;
end;
Ist von sowas dann abzuraten?

Die markierte Zeile unten kann dann vermutlich auch weg
Delphi-Quellcode:
procedure TForm2.VSTInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
begin
 Node.SetData<TVSTData>(aVSTDataClasses[Node.Index]);
 aVSTDataClasses[Node.Index].aNode := Node; // ----------------------------------------------
end;

Auch da hat er Recht wenn er sagt, dass das schlechtes Design ist. Die Daten sollten generell nie etwas von dem anzuzeigenden Control wissen. Wenn später irgendwelche Dinge mit den Daten passieren sollen, dann musst du das auf Datenebene machen. Und nicht dadurch, dass du durch die Nodes iterierst.
Genau so ist das auch umgekehrt. Wenn du die Daten aktualisiert, dann reicht ein VST.Invalidate(). Wenn Daten hinzugefügt oder gelöscht werden, dann solltest du die Daten auch im VST aktualisieren - sprich löschen und neu erstellen. Das ist das, was TiGü mit konsistentem Zustand meinte. Deine Daten im VST passen immer 100% zu den Daten in deiner ObjectList.


EDIT: Oh je. Jetzt ist es kein Edit mehr :D

günni0 17. Apr 2018 10:32

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Zitat:

Auch da hat er Recht wenn er sagt, dass das schlechtes Design ist.
Oh ich wollte nicht, dass ihr mich falsch versteht. Ich stelle eure aller Kenntnisse nicht in Frage.
Ich frage nur in die Runde.

Zitat:

Wenn Daten hinzugefügt oder gelöscht werden, dann solltest du die Daten auch im VST aktualisieren - sprich löschen und neu erstellen.
Also Clear aufrufen und RootNodeCount setzen. Dass das Setzen von RootNodeCount alles neuzeichnet, das muss man erst einmal wissen. Denn der Name sagt was komplett anderes.
Mit erstellen meinst du ja RootNodeCount setzen denke ich doch?

Zitat:

Die Daten sollten generell nie etwas von dem anzuzeigenden Control wissen
Den Satz werde ich mir merken.

TiGü 17. Apr 2018 10:45

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Wie ich sehe, nimmt das langsam vernünftige Formen an.
Höre auf das, was Aviator sagt. Er ist sehr erfahren mit dem VST.

Alternativ zum RootNodeCount und OnInitNode-Eventhandler kannst du natürlich auch versuchen mit AddChild zu arbeiten.
Delphi-Quellcode:
 
  // PseudoCode
  for deinTyp in deinerListe do
  begin
    vst.AddChild(nil, deinTyp);
  end;
Kommt auf das gleiche hinaus, aber vielleicht verstehst du das in zwei Monaten noch, wenn du dir den Code nochmal anguckst.

Aviator 17. Apr 2018 10:50

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Zitat:

Zitat von günni0 (Beitrag 1399500)
Zitat:

Auch da hat er Recht wenn er sagt, dass das schlechtes Design ist.
Oh ich wollte nicht, dass ihr mich falsch versteht. Ich stelle eure aller Kenntnisse nicht in Frage.
Ich frage nur in die Runde.

Ich habe das auch nicht falsch verstanden. Ich wollte nur die Aussage von TiGü untermauern und damit sagen, dass er das bereits korrekt gesagt hat. :)

Zitat:

Zitat von günni0 (Beitrag 1399500)
Zitat:

Wenn Daten hinzugefügt oder gelöscht werden, dann solltest du die Daten auch im VST aktualisieren - sprich löschen und neu erstellen.
Also Clear aufrufen und RootNodeCount setzen. Dass das Setzen von RootNodeCount alles neuzeichnet, das muss man erst einmal wissen. Denn der Name sagt was komplett anderes.
Mit erstellen meinst du ja RootNodeCount setzen denke ich doch?

Ja, das meine ich damit. Ich finde es ja schonmal gut, dass du überhaupt RootNodeCount nutzt. Das ist auch die richtige Vorgehensweise. Viele fangen mit AddChild() an und müssen sich dann irgendwann später wieder umstellen.

Zitat:

Zitat von TiGü (Beitrag 1399502)
Wie ich sehe, nimmt das langsam vernünftige Formen an.
Höre auf das, was Aviator sagt. Er ist sehr erfahren mit dem VST.

Danke für das Lob. :-D :thumb:

Zitat:

Zitat von TiGü (Beitrag 1399502)
Alternativ zum RootNodeCount und OnInitNode-Eventhandler kannst du natürlich auch versuchen mit AddChild zu arbeiten.
Delphi-Quellcode:
 
  // PseudoCode
  for deinTyp in deinerListe do
  begin
    vst.AddChild(nil, deinTyp);
  end;
Kommt auf das gleiche hinaus, aber vielleicht verstehst du das in zwei Monaten noch, wenn du dir den Code nochmal anguckst.

Bloß nicht. Zum Glück habe ich vorm Absenden deinen Post, der zwischenzeitlich erstellt wurde, nochmal gelesen. :)

Er ist mit RootNodeCount schon auf dem richtigen Weg. AddChild() ist zwar anfängerfreundlicher, aber wenn er sowieso schon richtig angefangen hat, dann sollten wir ihn auf keinen Fall auf die falsche Spur locken.

Anbei mal noch ein Auszug aus dem Source der VirtualTreeView Komponente (Hervorhebung von mir):

Zitat:

Zitat von VirtualTreeView Source
function TBaseVirtualTree.AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode;

// Adds a new node to the given parent node. This is simply done by increasing the child count of the
// parent node. If Parent is nil then the new node is added as (last) top level node.
// UserData can be used to set the first sizeof(Pointer) bytes of the user data area to an initial value which can be used
// in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet
// "officially" initialized.
// AddChild is a compatibility method and will implicitly validate the parent node. This is however
// against the virtual paradigm and hence I dissuade from its usage.


günni0 17. Apr 2018 11:11

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Delphi-Quellcode:
Höre auf das, was Aviator sagt. Er ist sehr erfahren mit dem VST.
Ich höre auf euch beide :thumb:

Eine Sache habe ich eben noch hinzugefügt

aus
Delphi-Quellcode:
procedure TForm2.Button2Click(Sender: TObject);
begin
 VST.Clear;
 DeleteNode(2); // Daten anhand des Index löschen. 2 ist nicht der absolute Index sondern der, der in Button1Click gesetzt wird
 VST.RootNodeCount := aVSTDataClasses.Count;
end;
wird

Delphi-Quellcode:
procedure DeleteUserNode(iIndex: Integer);
begin
 if iIndex > aVSTDataClasses.Count - 1 then // ---------------- neu
  Exit;

 VST.Clear;
 aVSTDataClasses.Delete(iIndex);
 VST.RootNodeCount := aVSTDataClasses.Count; // re-draws alle nodes of VST
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
 DeleteNode(2);
end;
Zitat:

Alternativ zum RootNodeCount und OnInitNode-Eventhandler kannst du natürlich auch versuchen mit AddChild zu arbeiten.
Zitat:

Bloß nicht.
Habe es eben dennoch mal ausprobiert.
Mein erstes Erlebnis waren Nodes die nicht richtig gezeichnet wurden, wenn man das AfterItemPaint-Event nutzt. Aber das war nur minimal und nicht weiter schlimm und auch sofort wieder weg, sobald man mit der Maus über den Node gefahren ist.

Aviator 17. Apr 2018 11:26

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Zitat:

Zitat von günni0 (Beitrag 1399506)
Delphi-Quellcode:
procedure DeleteUserNode(iIndex: Integer);
begin
 if iIndex > aVSTDataClasses.Count - 1 then // ---------------- neu
  Exit;

 VST.Clear;
 aVSTDataClasses.Delete(iIndex);
 VST.RootNodeCount := aVSTDataClasses.Count; // re-draws alle nodes of VST
end;

Da sind wir dann jetzt schon beim ErrorHandling. Aber das ist ok. Alternativ zum
Delphi-Quellcode:
Exit
könntest du es auch so machen. Sieht eventuell besser aus:
Delphi-Quellcode:
procedure DeleteUserNode(iIndex: Integer);
begin
  if (iIndex > -1) and (iIndex < aVSTDataClasses.Count) then begin
    VST.Clear;
    aVSTDataClasses.Delete(iIndex);
    VST.RootNodeCount := aVSTDataClasses.Count; // re-draws all nodes of VST
  end;
end;


Zitat:

Zitat von günni0 (Beitrag 1399506)
Zitat:

Alternativ zum RootNodeCount und OnInitNode-Eventhandler kannst du natürlich auch versuchen mit AddChild zu arbeiten.
Zitat:

Bloß nicht.
Habe es eben dennoch mal ausprobiert.
Mein erstes Erlebnis waren Nodes die nicht richtig gezeichnet wurden, wenn man das AfterItemPaint-Event nutzt. Aber das war nur minimal und nicht weiter schlimm und auch sofort wieder weg, sobald man mit der Maus über den Node gefahren ist.

Dazu eine kleine Sache. Das hast du zwar in dem anderen Thread geschrieben, aber da du es jetzt gerade hier ansprichst. Die Änderung der Schriftfarbe solltest du im OnPaintText oder im OnDrawText Event durchführen. OnAfterCellPaint bzw. OnAfterItemPaint sind die Events, die eigentlich nur noch ausgelöst werden, wenn du unabhängig von Text und Images noch etwas in die jeweiligen Cells malen möchtest. Beispielsweise ein Flag, wenn du irgendwann mal Daten im VST geändert hast (mit den Inplace Editoren; da wirst du bestimmt auch irgendwann mal hinkommen).


Anbei mal die Reihenfolge der Events (Auszug aus der Hilde des VST):
Zitat:

Zitat von PaintEvents
Usually the following paint stages are executed during a paint cycle:
  • before paint (OnBeforePaint)
  • before item paint (OnBeforeItemPaint)
  • before item erase (OnBeforeItemErase)
  • after item erase (OnAfterItemErase)
  • before cell draw (OnBeforeCellPaint)
  • on paint text (string trees only, OnPaintText)
  • after cell draw (OnAfterCellPaint)
  • after item paint (OnAfterItemPaint)
  • after paint (OnAfterPaint)


günni0 17. Apr 2018 11:30

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Ich lasse mir zusätzlich zum normalen Node-Text noch eine weitere Zeichenkette ausgeben. Das erledige ich in AfterItemPaint mit TargetCanvas und DrawTextW.

Aviator 17. Apr 2018 11:38

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
Zitat:

Zitat von günni0 (Beitrag 1399509)
Ich lasse mir zusätzlich zum normalen Node-Text noch eine weitere Zeichenkette ausgeben. Das erledige ich in AfterItemPaint mit TargetCanvas und DrawTextW.

Zeig mal den Auszug. Für Text solltest du dich auf die dafür vorgesehenen Events festlegen. Im normalen GetText Event gibt es auch noch den Unterschied zwischen TextType Normal und TextType Static. Da solltest du evtl. auch mal einen Blick drauf werfen.

Oder eben das DrawText Event. Da bist du vollkommen frei und kannst alles selbst malen was dir in den Sinn kommt. Hauptsache es handelt sich um Text und nicht um irgendwelche Cell spezifischen Dinge.

AfterItemPaint ist dafür eigentlich ungünstig.

EDIT: Vorteil von ttNormal und ttStatic ist, dass der Tree automatisch den Text mit "..." gekürzt abschneidet wenn er nicht passen sollte. Das musst du sonst selbst machen wenn es optisch nach etwas aussehen sollte. Oder du benutzt die Option ColumnSpan, dann zeichnet er den Text in die nächste Column sofern da kein Text steht.

Aviator 17. Apr 2018 12:19

AW: VirtualStringTree und Klasseninstanzen - Node Data finden
 
:idea: Für alle die sich wundern wieso hier aktuell nichts mehr passiert: Die Diskussion ging vorerst mal per PM weiter, da im gezeigten SourceCode evtl. sensible Daten enthalten sein könnten.


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