Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi VirtualTreeView: Es klappt nicht ganz (https://www.delphipraxis.net/70508-virtualtreeview-es-klappt-nicht-ganz.html)

JPSelter 31. Mai 2006 13:38

Re: VirtualTreeView: Es klappt nicht ganz
 
Das hab ich jetzt nicht so erwartet ;) Nochmal gaaaanz langsam:

Problem 1: Speichern. Wie speichere ich ein Objekt? Übernimmt das Programm die interne Verwaltung der internen Objekt-Daten oder muss ich manuell an die Daten ran? Im Moment speichere ich ganz einfach das Objekt in den Stream. Er macht das auch ohne zu murren und in der Datei auf der Festplatte sehe ich einen der internen Strings (aber nur diesen einen) und jede Menge anderes ASCII-Zeugs, das für mich als Betrachter sicher nicht wichtig ist.

Problem 2 stelle ich erst, wenn das Speichern funktioniert ;)

himitsu 31. Mai 2006 13:44

Re: VirtualTreeView: Es klappt nicht ganz
 
Du speicherst nur einen Pointer auf das Objekt in den Stream ... das Objekt selber ist nicht in der VTV ... genaus wird es mit dem String gemacht (halt nur der Pointer auf den String in der VTV), nur das man da halt auf den Referenzzähler achten muß.

Du kannst natürlich den String auch in einem ShortString (String[255], odeer so) speichern, wobei der hortString wieder nur ein Record wäre und somit selbst in der VTV landet.


PS: hatte oben noch einiges nachgetragen.

JPSelter 31. Mai 2006 13:54

Re: VirtualTreeView: Es klappt nicht ganz
 
Puh, oje, das ist mir im Moment etwas zu hoch... kannst Du mir vielleicht etwas konkreten Code zu meinem konkreten Objekt (hier ganz oben) geben? :|

generic 31. Mai 2006 14:04

Re: VirtualTreeView: Es klappt nicht ganz
 
warum macht ihr alle das so umständlich.

schaut euch bitte von mir nochmal folgenden beispielcode an:
http://www.delphipraxis.net/internal...=484809#484809

himitsu 31. Mai 2006 14:06

Re: VirtualTreeView: Es klappt nicht ganz
 
zu deinem Projekt steht's ja sozusagen schon dort oben (Beitrag #7)

Du muß halt bedenken, das dein Objekt ja nicht nur aus einem zusammenhängendem Speicherblock besteht.
Var irgendwas: TSessionObject; ist halt nur ein Pointer auf das Objekt und in dem Objekt sind ja auch wiederum Pointer auf andere Dinge (z.B. die Strings).

Also, will man jetzt ein Objekt "nur" mit der VTV verbinden, dann stimmt das schon, aber die gesamten Daten eines Objekts in einen Stream zu bekommen ist nicht so leicht ... man kann da eigentlich nur das Objekt zerlegen und eine Kopie der einzelnen ObjektDaten in dem Stream speichern und müßte dann daraus (beim Auslesen) dann wieder ein neues Objekt erstellen.

JPSelter 31. Mai 2006 14:09

Re: VirtualTreeView: Es klappt nicht ganz
 
@generic: Von OnLoad und OnSave steht da aber nichts drin ;)

Ich probiere nun, die Daten des Objekts einzeln in den Stream zu schreiben (erstmal nur der erste Parameter) mit

Delphi-Quellcode:
// save nodes to disk
procedure TForm1.VST1SaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Data: PTreeData;
  Len: integer;
begin
  Data := VST1.GetNodeData(Node);
  Len := Length(TSessionObject(Data.FObject).name);
  Stream.Write(Len, SizeOf(Len));
  Stream.write(PChar(TSessionObject(Data.FObject).name)^, Len);
end;
Funktioniert soweit. Nur wie bekomme ich die Daten da wieder raus?

Delphi-Quellcode:
// load nodes from disk
procedure TForm1.VST1LoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Data: PTreeData;
  Len: integer;
begin
  Data := VST1.GetNodeData(Node);
  Stream.read(Len, SizeOf(Len));
  SetLength(TSessionObject(Data.FObject).name, Len); //<---- Error: Ein Konstantenobjekt kann nicht als Var-Parameter übergeben werden
  Stream.read(PChar(TSessionObject(Data.FObject).name)^, Len);
end;
Das klappt irgendwie nicht, wegen der markierten Zeile. Wieso?

JPSelter 31. Mai 2006 14:13

Re: VirtualTreeView: Es klappt nicht ganz
 
Ah, jetzt verstehe ich Dich ;) Dann muss ich das Objekt beim Laden ja neu erstellen durch ein Create. Dann mach ich das mal...

JPSelter 31. Mai 2006 14:35

Re: VirtualTreeView: Es klappt nicht ganz
 
OK, jetzt habe ich folgenden Code und eine EAccessViolation:

Delphi-Quellcode:
// save nodes to disk
procedure TForm1.VST1SaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Data: PTreeData;
  Len: integer;
begin
  Data := VST1.GetNodeData(Node);
  Stream.Write(TSessionObject(Data.FObject).datum, SizeOf(TSessionObject(Data.FObject).datum));
  Len := Length(TSessionObject(Data.FObject).name);
  Stream.Write(Len, SizeOf(Len));
  Stream.write(PChar(TSessionObject(Data.FObject).name)^, Len);
  //[... die restlichen Parameter]
end;
Delphi-Quellcode:
// load nodes from disk
procedure TForm1.VST1LoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  Data: PTreeData;
  Len,datum,ndatum: integer;
  SessionObject: TSessionObject;
  name,sessiontyp,protokollant,teilnehmer,verteiler: string;
begin
  Data := VST1.GetNodeData(Node);
  SessionObject:=TSessionObject.Create;

  Stream.Read(datum, SizeOf(datum));
  Stream.read(Len, SizeOf(Len));
  SetLength(name, Len);
  Stream.read(name, Len);
  // [... + der rest]

  SessionObject.datum:=datum;
  SessionObject.name:=name; // <--------------- hier kommt die Exception
  // [... + der rest]

  Data^.FObject:=SessionObject;
end;
Aber wieso die Exception? Irgendwo ein Pointer oder ein Objekt nicht richtig?

EDIT: Habe die Zeile markiert, wo die Exc geworfen wird. Muss aber jetzt leider für heute weg. Komme beim nächsten Arbeitstag wieder auf diesen Thread zurück. Danke soweit! :)

Hawkeye219 31. Mai 2006 15:13

Re: VirtualTreeView: Es klappt nicht ganz
 
Der Code zum Lesen der String-Var ist nicht ganz richtig. So ist es besser:

Delphi-Quellcode:
Stream.read(Len, SizeOf(Len));
SetLength(name, Len);
// Stream.read(name, Len);  // <-- name ist nur ein Zeiger!
if (Len > 0) then
  Stream.read(name[1], Len);
Gruß Hawkeye

himitsu 31. Mai 2006 15:16

Re: VirtualTreeView: Es klappt nicht ganz
 
Wo kommt den der Fehler und warum willst du unbedingt das gesamte Objekt din haben?
Es ist zumindestens Platzsparender, wenn nur der Pointer in der VTV steht und man bräuchte dann das Objekt nicht zu zerlegen...

Aber versuch es mal so:
Delphi-Quellcode:
Stream.Write(TSessionObject(Data.FObject).Name[1], Len);
Stream.Read(TSessionObject(Data.FObject).Name[1], Len);
oder
Delphi-Quellcode:
Stream.Write(@TSessionObject(Data.FObject).Name[1], Len);
Stream.Read(@TSessionObject(Data.FObject).Name[1], Len);
Ich weiß nicht, ob Write/Read 'nen VAR-Parameter (ersteres), oder 'nen Pointer (zweiteres) will.

[add]
OK, Markierung gesehn ^^

Dann lag es bestimmt an der Stringübergabe (siehe Code)
[/add]

PS: @generic
Na ja, eigentlichj ist es von der interen Speicherung in der VTV her egal wo man die Daten übergibt, aber wie man sie übergibt/ließt ist da schon wichtig.
Delphi-Quellcode:
vst.addchild(nil, [b]Data[/b]);

[i][b]Pointer[/b][/i] := [b]Data[/b];
vst.addchild(nil, [i][b]Pointer[/b][/i]);

N := vst.addchild(nil);
AVST.SetNodeData(N, [b]Data[/b]);

[i][b]Pointer[/b][/i] := [b]Data[/b];
n := vst.addchild(nil);
AVST.SetNodeData(N, [i][b]Pointer[/b][/i]);

... // vieles, vieles mehr
Hier ist ja mehr das Problem, wie die Daten in der VTV gespeichert/verwaltet sollen.






So, nun noch der wohl einfachere Weg ... das Objekt erzeigen und nur die referenz daruf übergeben:
Delphi-Quellcode:
procedure insertSession();
var SessionObject: TSessionObject;
begin
  SessionObject := TSessionObject.Create;
  SessionObject.datum:=DateTimeToUnix(Form1.DateTimePicker1.Date);
  SessionObject.sessiontyp:=Form1.ComboBox1.Text;
  SessionObject.protokollant:=Form1.Edit1.text;
  SessionObject.teilnehmer:=Form1.Edit2.Text;
  SessionObject.verteiler:=Form1.Edit3.Text;
  SessionObject.ndatum:=DateTimeToUnix(Form1.DateTimePicker2.Date);
  Result:=Form1.VST1.AddChild(nil, SessionObject);
end;

Diese kann auch ins OnCreate der Form (falls man es nicht auch direkt im OI ändern kann/will) ... einmal reicht ja, die Größe ändert sich ja nicht (PS: SizeOf(TTreeData) = Pointer = 4 Byte, also 4)
Delphi-Quellcode:
VST1.NodeDataSize:=SizeOf(TTreeData);
Delphi-Quellcode:
procedure deleteSession(Node: PVirtualNode);
var SessionObject: TSessionObject;
begin
  TSessionObject(Form1.VST1.GetNodeData(Node)).Free;
  Form1.VST1.Delete; // keine Ahnung ob das wirklich so heißt
end;

Folgendes kann auch ins OnCreate der Form (falls man es nicht direkt im OI ändern kann/will) ... einmal reicht ja, die Größe ändert sich schließlich nicht (PS: SizeOf(TTreeData) = Pointer = 4 Byte, also 4)
Delphi-Quellcode:
VST1.NodeDataSize:=SizeOf(TTreeData);


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:18 Uhr.
Seite 2 von 3     12 3      

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