Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Saving Icons to Stream

Status
Not open for further replies.

sggaunt

Programmer
Jul 4, 2001
8,620
GB
I adapted a function to write some object properties (in a TList) to a File stream

I think it should be possible to save Any properties in this way, it works OK for Integers, strings (fixed length) even simple enumerated types but if I Use the same method for an Icon (ObjectIco is a TIcon), it dosent work.


procedure TThings.WriteToStream(Fs : TFileStream );
begin
Fs.WriteBuffer(XPos, Sizeof(Xpos));
Fs.WriteBuffer(YPos, Sizeof(Ypos));
Fs.WriteBuffer(ObjectIco, Sizeof(ObjectIco));
end;

Does anyone know the correct way to do this ??
Steve.
 

procedure TThings.WriteToStream(Fs : TFileStream );
begin
Fs.WriteBuffer(XPos, Sizeof(Xpos));
Fs.WriteBuffer(YPos, Sizeof(Ypos));
ObjectIco.SaveToStream(fs);
end;
 
Tried that, It did seem to be saving OK? (the resulting file was larger), But I couldnt get it to reload with the equivalent ObjectIco.Loadfromstream (Horrible access violation crash).
Is there some creation issue here?

Steve
 
Can you post the code that you used both to save and load the x, y positions and the icon?

Andrew
 
Ok You ased for it:-

I thought you might need a bit more background so
The objects are made part of a TList so we can use the Savetostream methods

The code is based on PCPlus Tutorial on how to save mixed objects.


TObjectList = Class(TList)
procedure AddObject(Index: integer;
ObjectName: TextStr; // a fixed length string
status: Integer;
Moveable: Boolean;
Position: Integer;
Ten: Tenses;
Text: array of TStringList;
XPos,YPos: integer;
Image: TIcon);
procedure SaveObjects(fname : string );
procedure LoadObjects(fname: string);
end;

TThings = class(TObject)
objectico: TIcon;
Index: integer;
ObjectName: TextStr;
Status: integer;
Moveable: Boolean;
Position: integer;
Tense: Tenses;
Text: array[0..5] of TstringList; // we will have to save the length of the strings!!
XPos: integer;
YPos: integer;
procedure WriteToStream( Fs: TFileStream );
procedure ReadFromStream(Fs: TFileStream);
constructor CreateFromStream(Fs : TFileStream );
private

public

constructor make(item: integer; obj: TextStr; place: integer; stat: integer;
m: boolean; ten: tenses;
Txt: array of TstringList;
x,y:integer;
Image: TIcon);

end;

In the implementation these procedures do the TThing Load/save :-


procedure TThings.WriteToStream(Fs : TFileStream );
var A, B, C: integer;
LineofText: TextStr;
begin
// Here we cannont attempt to save the string list array so we must extratct
// the text and store it as a simple strings

Fs.WriteBuffer(Index, Sizeof(Index));
Fs.WriteBuffer(ObjectName, Sizeof(ObjectName));
Fs.WriteBuffer(Status, Sizeof(Status));
Fs.WriteBuffer(Moveable, Sizeof(Moveable));
Fs.WriteBuffer(Position, Sizeof(Position));
Fs.WriteBuffer(Tense, Sizeof(Tense));

C := 0;
for a := 0 to 5 do
begin
C := text[a].count;
Fs.WriteBuffer(C, Sizeof(C)); // store number of strings on each page
for b := 0 to C - 1 do
begin
LineofText := Text[a].strings;
Fs.WriteBuffer(LineofText, sizeof(LineofText));
end;

end;

Fs.WriteBuffer(XPos, Sizeof(Xpos));
Fs.WriteBuffer(YPos, Sizeof(Ypos));
ObjectIco.SaveToStream(Fs);



end;

procedure TThings.ReadFromStream(Fs: TFileStream);
var A,B,C: integer;
LineofText: TextStr;
begin
Fs.ReadBuffer(Index, sizeof(Index));
Fs.ReadBuffer(ObjectName, sizeof(ObjectName));
Fs.ReadBuffer(Status, Sizeof(Status));
Fs.ReadBuffer(Moveable, sizeof(Moveable));
Fs.ReadBuffer(Position, Sizeof(Position));
Fs.ReadBuffer(Tense, Sizeof(Tense));

// As you can see I also had a problem with the TStringlist field and got round it by
// extracting it to Fixed length strings. The sring list is implictly created here I thought // this might be a clue but doing simular diddnt seem to work with the Icon type.

C := 0;
for A := 0 to 5 do
begin
Fs.ReadBuffer(C, Sizeof(C));
Text[a] := Tstringlist.create;
for b := 0 to C - 1 do
begin
Fs.ReadBuffer(LineofText, sizeof(LineofText));
Text[a].Add(LineofText);
end;
end;

Fs.ReadBuffer(XPos, Sizeof(Xpos));
Fs.ReadBuffer(YPos, Sizeof(Ypos));

ObjectIco.LoadFromStream(Fs); // Here lieth the crash.

end;


At the TList level these are the procedures called by the main form Load/save Actions
If it seems over complex? This is because the other modules have 2 Types of object (none with icons or the like) and the writetostream Procedures are virtual so looping through the TList only need to make one call.
I intend to add this module into the main TList (when I can get it to work).

procedure TObjectList.SaveObjects(Fname : string );
var Fs : TFileStream;
I : integer;
begin
// create a File stream object
Fs := TFileStream.Create(Fname, fmCreate);
try
for i := 0 to ObjList.Count - 1 do
// cast The ObjectList object to a TThing
TThings(ObjList).WriteToStream(Fs);
finally;
Fs.Free;
end;
end;

procedure TObjectList.LoadObjects(Fname : string );
var Fs : TFileStream;
begin
Fs := TFileStream.Create(Fname, fmOpenRead);
try
//read in the object data and create each object as we read it.
while Fs.Position < Fs.Size do
begin
ObjList.Add(TThings.CreateFromStream(Fs));
inc(NumberOfObjects);
end;
finally;
Fs.Free;
end;
end;

The constructer works fine and I am able to create the icons in memory no problem with these two lines

ObjectIco := TIcon.Create;
ObjectIco.Assign(Image);

Where image is a Tcon Passed in from a TImage as Image.picture.icon.

Steve..


 
Thanks (!)

A couple of points I don't understand in your code. How does this line work?
Code:
  LineofText := Text[a].strings;
LineOfText is (presumably) an array of char and strings is not.

However, I suspect that in your ReadFromStream method whilst you are creating your TStringLists with
Code:
  Text[a] := Tstringlist.create;
there is no equivalent creation of ObjectIco and this would cause it to crash at
Code:
  ObjectIco.LoadFromStream(Fs); // Here lieth the crash.
If you stop the debugger at this line, does ObjectIco have a value of nil?

Andrew
 
Cheers Andrew

Something got lost in the cut and paste the string list thing should read

LineofText := Text[a].strings;

After I posted I tried :-

ObjectIco := TIcon.Create;
ObjectIco.LoadFromStream(Fs);

Which Now Works!! (I am sure I tried this before?, I must be suffering from one of the same problems as MerryMadDad.)

There is still a problem though, as you can see this is supposed to save a list of Objects, and looking at the saved file It does.

But now when I read back it only seems to read 1 object

while Fs.Position < Fs.Size do

This loop is only executing Once no matter how many objects are saved and Fs.Position goes from 0 to the File size in one step. again before adding the icon this seemed to work Ok.??

Steve







 
Failed to copy correctly again I see

LineofText := Text[a].strings;

steve
 
LineofText := Text[a].strings(square bracket b square bracket);
for some reason this editor wont accept the second set of brackets
 
The reason the editor won't accept the second set of square brackets surrounding the b is that it interprets this as a command to format the following text in bold!

I haven't time to look at your problem until tomorrow. Maybe someone else can help meanwhile?

Andrew
 
I suspect that ObjectIco.LoadFromStream loads the entire stream from the current position. I guess you will need to save the length of the icon in the stream before saving the icon. Then when reading it back use a stream.Read to get the length of the icon and then read the icon with the read length.

Andrew
 
Cheers Andrew
Sounds feasible, I will it.

Steve
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top