ScottCannon
asked on
Delphi XE and VirtualStringTree 4.8.7 - Saving and loading data
I'm having a problem saving and loading the nodes of the VirtualStringTree.
Please explain where the problem is and how to fix it.
type
PNodeData = ^TNodeData;
TNodeData = record
Caption: String;
Filename: String;
Description: String;
FileDateTime: TDateTime;
ImageIndex: Byte;
ID: Integer;
end;
procedure MainForm.TreeSaveNode (Sender: TBaseVirtualTree;
Node: PVirtualNode; Stream: TStream);
var
Data: PNodeData;
Len: integer;
begin
Data := Tree.GetNodeData(Node);
Len := Length(Trim(Data^.Caption) );
Stream.write(Len, SizeOf(Len));
Stream.write(Data^.Caption , Len * SizeOf(Char));
Len := Length(Trim(Data^.Filename ));
Stream.write(Len, SizeOf(Len));
Stream.write(Data^.Filenam e, Len * SizeOf(Char));
Len := Length(Trim(Data^.Descript ion));
Stream.write(Len, SizeOf(Len));
Stream.write(Data^.Descrip tion, Len * SizeOf(Char));
Stream.write(Data^.FileDat eTime, SizeOf(Data^.FileDateTime) );
Stream.Write(Data^.ImageIn dex, SizeOf(Data^.ImageIndex));
Stream.Write(Data^.ID, SizeOf(Data^.ID));
end;
procedure MainForm.TreeLoadNode(Send er: TBaseVirtualTree;
Node: PVirtualNode; Stream: TStream);
var
Data: PNodeData;
Len: integer;
begin
Data := Tree.GetNodeData(Node);
Stream.Read(Len, SizeOf(Len));
SetLength(Data^.Caption, Len);
Stream.Read(Data^.Caption, Len * SizeOf(Char));
Stream.Read(Len, SizeOf(Len));
SetLength(Data^.Filename, Len);
Stream.Read(Data^.Filename , Len * SizeOf(Char));
Stream.Read(Len, SizeOf(Len));
SetLength(Data^.Descriptio n, Len);
Stream.Read(Data^.Descript ion, Len * SizeOf(Char));
Stream.Read(Data^.FileDate Time, SizeOf(Data^.FileDateTime) );
Stream.Read(Data^.ImageInd ex, SizeOf(Data^.ImageIndex));
Stream.Read(Data^.ID, SizeOf(Data^.ID));
end;
Please explain where the problem is and how to fix it.
type
PNodeData = ^TNodeData;
TNodeData = record
Caption: String;
Filename: String;
Description: String;
FileDateTime: TDateTime;
ImageIndex: Byte;
ID: Integer;
end;
procedure MainForm.TreeSaveNode (Sender: TBaseVirtualTree;
Node: PVirtualNode; Stream: TStream);
var
Data: PNodeData;
Len: integer;
begin
Data := Tree.GetNodeData(Node);
Len := Length(Trim(Data^.Caption)
Stream.write(Len, SizeOf(Len));
Stream.write(Data^.Caption
Len := Length(Trim(Data^.Filename
Stream.write(Len, SizeOf(Len));
Stream.write(Data^.Filenam
Len := Length(Trim(Data^.Descript
Stream.write(Len, SizeOf(Len));
Stream.write(Data^.Descrip
Stream.write(Data^.FileDat
Stream.Write(Data^.ImageIn
Stream.Write(Data^.ID, SizeOf(Data^.ID));
end;
procedure MainForm.TreeLoadNode(Send
Node: PVirtualNode; Stream: TStream);
var
Data: PNodeData;
Len: integer;
begin
Data := Tree.GetNodeData(Node);
Stream.Read(Len, SizeOf(Len));
SetLength(Data^.Caption, Len);
Stream.Read(Data^.Caption,
Stream.Read(Len, SizeOf(Len));
SetLength(Data^.Filename, Len);
Stream.Read(Data^.Filename
Stream.Read(Len, SizeOf(Len));
SetLength(Data^.Descriptio
Stream.Read(Data^.Descript
Stream.Read(Data^.FileDate
Stream.Read(Data^.ImageInd
Stream.Read(Data^.ID, SizeOf(Data^.ID));
end;
ASKER
I emplemented your changes and it still has the following issue.
I have this code assigned to the tree OnChange event.
if not Assigned(Node) then
Exit;
Data := Tree.GetNodeData(Node);
Filename.Text := Data^.Filename;
Description.Text := Data^.Description;
ID.Text := IntToStr(Data^.ID);
Moving between nodes, the data is displayed correctly.
If I save the tree and open it, I don't receive any errors but when I change nodes the first half of the data displayed is correct and the second half is wrong. (i.e. GeneralPurpose.pdf in the Filename becomes GeneralPuDivision).
I have this code assigned to the tree OnChange event.
if not Assigned(Node) then
Exit;
Data := Tree.GetNodeData(Node);
Filename.Text := Data^.Filename;
Description.Text := Data^.Description;
ID.Text := IntToStr(Data^.ID);
Moving between nodes, the data is displayed correctly.
If I save the tree and open it, I don't receive any errors but when I change nodes the first half of the data displayed is correct and the second half is wrong. (i.e. GeneralPurpose.pdf in the Filename becomes GeneralPuDivision).
Sorry for not replying sooner. I'll take a look at this again later today or tomorrow morning
ASKER
Any idea what might be causing the corruption of the stings? I've inspected the data prior to saving it to the stream and it is valid. Inspecting is as it is being read from the stream it is corrupted.
This still does not tell me if it is corrupted when it is written out or when it is read in.
This still does not tell me if it is corrupted when it is written out or when it is read in.
I'm currently debugging it, I created random 50 records and seems I always get the correct results.
I'm yet to try with different length strings, I'll definietly find the offending code, and I can also suggest a more robust way saving the data.
ASKER
Any suggestions on a better way of saving the data would be appreciated.
Ok, I found the problem, I just could not recreate until I switched to Delphi 2010
You have to Typecast the strings as PChar. Also, use the Sender parameter from the method signature
procedure TMainForm.TreeLoadNode(Sender: TBaseVirtualTree;
Node: PVirtualNode; Stream: TStream);
var
Data: PNodeData;
Len: Integer;
begin
Data := Sender.GetNodeData(Node);
Stream.Read(Len, SizeOf(Len));
SetLength(Data.Caption, Len);
Stream.Read(PChar(Data.Caption)^, Len * SizeOf(Char) );
Stream.Read(Len, SizeOf(Len));
SetLength(Data.Filename, Len);
Stream.Read(PChar(Data.Filename)^, Len * SizeOf(Char));
Stream.Read(Len, SizeOf(Len));
SetLength(Data.Description, Len);
Stream.Read(PChar(Data.Description)^, Len * SizeOf(Char));
Stream.Read(Data.FileDateTime, SizeOf(Data.FileDateTime));
Stream.Read(Data.ImageIndex, SizeOf(Data.ImageIndex));
Stream.Read(Data.ID, SizeOf(Data.ID));
end;
procedure TMainForm.TreeSaveNode(Sender: TBaseVirtualTree;
Node: PVirtualNode; Stream: TStream);
var
Data: PNodeData;
Len: integer;
begin
Data := Sender.GetNodeData(Node);
Len := Length(Data.Caption);
Stream.write(Len, SizeOf(Len));
Stream.write(PChar(Data.Caption)^, Len * SizeOf(Char));
Len := Length(Data^.Filename);
Stream.write(Len, SizeOf(Len));
Stream.write(PChar(Data.Filename)^, Len * SizeOf(Char));
Len := Length(Data^.Description);
Stream.write(Len, SizeOf(Len));
Stream.write(PChar(Data.Description)^, Len * SizeOf(Char));
Stream.write(Data.FileDateTime, SizeOf(Data.FileDateTime));
Stream.Write(Data.ImageIndex, SizeOf(Data.ImageIndex));
Stream.Write(Data.ID, SizeOf(Data.ID));
end;
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
This works perfectly. Thanks for the great work!
You mentioned that you would suggest a more robust way of saving the data... any more thought on doing so and maybe an example?
You mentioned that you would suggest a more robust way of saving the data... any more thought on doing so and maybe an example?
You are storing the wrong sizes, and also using TRIM when getting length but not when saving
Cast as Untyped pointer as well
Open in new window