2 Stimmen

Schreiben von Daten in PVirtualNode ohne manuelle Einstellung der einzelnen Feldwerte

Nehmen wir an, ich habe diesen Knoten-Datensatz:

Type
  PPerson = ^TPerson;
  TPerson = record
   Name: String;
   Age: Integer;
   SomeBool: Boolean;
  end;

Um meinen VirtualStringTree aufzufüllen, würde ich folgendes tun:

Procedure AddToTree(Person: TPerson);
Var
 Node: PVirtualNode;
 Data: PPerson;
Begin
 Node := VT.AddChild(nil);
 Data := VT.GetNodeData(Node);
 Data.Name := Person.Name;
 Data.Age  := Person.Age;
 Data.SomeBool := Person.SomeBool;
End;

Procedure TMyForm.MyButtonClick(Sender: TObject);
Var
 Person: TPerson;
Begin
 Person.Name := 'Jeff';
 Person.Age := 16;
 Person.SomeBool := False;
 AddToTree(Person);

End:

Nun, während dies funktioniert völlig in Ordnung, ich möchte es zu vereinfachen, so dass jedes Mal, wenn ich neue Felder zum Datensatz hinzufügen, ich nicht die AddToTree-Methode ändern müssen.

Also habe ich dies versucht:

Procedure AddToTree(Person: TPerson);
Begin
 VT.AddChild(nil,@Person);
End;

Dies kompiliert, sondern scheint es, dass die PVirtualNode habe die Daten nicht erhalten, weil mein VT nichts anzeigt, und wenn ich im OnGetText-Ereignis breche, sehe ich, dass die Variablen leer sind.

Was mache ich falsch? :)

5voto

Rob Kennedy Punkte 158781

Datensätze unterstützen den Zuweisungsoperator:

procedure AddToTree(const Person: TPerson);
var
  Node: PVirtualNode;
  Data: PPerson;
begin
  Node := VT.AddChild(nil);
  Data := VT.GetNodeData(Node);
  Data^ := Person;
end;

3voto

ain Punkte 22039

Sie haben das Handbuch nicht gelesen :)

OK, in diesem Fall ist die Quelle das Handbuch - Zitat aus dem AddChild() Quelle:

UserData kann verwendet werden, um die ersten 4 Bytes des Nutzdatenbereichs auf einen Anfangswert zu setzen in OnInitNode verwendet werden kann und auch das OnFreeNode-Ereignis auslöst (wenn <> nil), selbst wenn der Knoten noch nicht noch nicht "offiziell" initialisiert ist.

D.h. es ist nicht dafür gedacht, so verwendet zu werden, wie Sie es verwenden bzw. erwarten, dass es funktioniert.

Übrigens: Warum kopieren Sie Daten? Warum haben Sie nicht

type
  PTreeData = ^TTreeData;
  TTreeData = record
   Data: PPerson;
  end;

und ordnen Sie Datensätze mit New() sie im Baum halten und dann Dispose() wenn der Baum gerodet wird?

3voto

Fr0sT Punkte 2809

Die beste Art, Daten in VTV zu speichern, wenn Datensätze als Datenträger verwendet werden, besteht darin, nur Zeiger auf die Datensätze zu speichern, während die Datensätze selbst separat in einer Liste/Array gespeichert werden. Dies entspricht auch einem virtuellen und MVC-Paradigma, wenn die visuelle Komponente nicht wirklich Daten besitzt. IOW, das Schema des Hinzufügens eines Datensatzes ist:

  • Speicher für den Datensatz zuweisen (!) mit AllocMem, New, ...
  • Füllen Sie die Felder aus
  • Hinzufügen zur Liste/zum Array
  • Neuen Knoten zu VTV hinzufügen mit NodeData = PNewRecord

und das Schema für die Löschung eines Datensatzes ist:

  • Entsprechenden Knoten aus VTV löschen
  • Datensatz mit Finalize (!) abschließen, um Speicherlecks mit ref-gezählten Feldern
  • Zugewiesenen Speicher mit FreeMem, Dispose, ... entsorgen
  • Element aus Liste/Array löschen

0voto

Jeff Punkte 11732

Und wieder ein "Ich habe die Antwort 2 Minuten, nachdem ich die Frage gestellt habe, gefunden" - wie demütigend... :(

Wie auch immer, so - dies kann durch die Verwendung von CopyMemory, wie folgt erreicht werden:

Procedure AddToTree(Person: TPerson);
Var
 Data: PPerson;
 Node: PVirtualNode;
Begin
 // add node
 Node := VT.AddChild(nil);
 // Get data of the node
 Data := VT.GetNodeData(Node);
 // Copy the Person stuff to the Node's data.
 CopyMemory(Data,@Person,SizeOf(Person));
End;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X