Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help with String Grid

80 views
Skip to first unread message

Trevor Southam

unread,
Jul 21, 2000, 3:00:00 AM7/21/00
to
Hi
Does anyone know how to save StringGrid text and objects in cells to and
from a file. I have to save the grid on every change to a cell and
restore it in the event of a crash or power failure. I have got the text
part working (sort of) but not the objects.
I'm using Delphi 4.

Thanks

Trevor

Sundial Services

unread,
Jul 21, 2000, 3:00:00 AM7/21/00
to
Well, Trevor, there is no "built-in" support for doing such a thing ...
and given that you're well on your way on the text part of it, I must
now break the news to you that "the objects are the problem."

I have no way to know what the objects are, exactly, but it does occur
to me that perhaps you could write the name of the object to a stream
and then (maybe!) call the "SaveToStream" method for that object ... and
thereby somehow come fairly close to getting where you want to go. Your
corresponding restore logic would have to be able to read the name from
the stream, create the object, have it read-from-stream ... umm, as I
write this, I must admit it's sounding hairier and hairier, trickier and
trickier, all the time.

/mr/

------------------------------------------------------------------
Sundial Services :: Scottsdale, AZ (USA) :: (480) 946-8259
mailto:in...@sundialservices.com (PGP public key available.)
> Fast(!), automatic table-repair with two clicks of the mouse!
> ChimneySweep(R): "Click click, it's fixed!" {tm}
> http://www.sundialservices.com/products/chimneysweep

AlanGLLoyd

unread,
Jul 22, 2000, 3:00:00 AM7/22/00
to
In article <3978AC3F...@starcomms.co.uk>, Trevor Southam
<dev...@starcomms.co.uk> writes:

>Does anyone know how to save StringGrid text and objects in cells to and
>from a file. I have to save the grid on every change to a cell and
>restore it in the event of a crash or power failure. I have got the text
>part working (sort of) but not the objects.
>I'm using Delphi 4.
>

Depends on what your objects are. If they are complex then it may be difficult,
as every property of the object must be saved. Give us a bit more detail on
this aspect.

Alan Lloyd
alang...@aol.com

Clairebear

unread,
Jul 22, 2000, 3:00:00 AM7/22/00
to
When you store an associated 'object' (if you are using something like
cols.addobject method) you are just storing a pointer and not the object
itself.
Which is why you cant just write it to file, cos the pointer means nothing
when your application reruns.

Trevor Southam <dev...@starcomms.co.uk> wrote in message
news:3978AC3F...@starcomms.co.uk...
> Hi


> Does anyone know how to save StringGrid text and objects in cells to and
> from a file. I have to save the grid on every change to a cell and
> restore it in the event of a crash or power failure. I have got the text
> part working (sort of) but not the objects.
> I'm using Delphi 4.
>

> Thanks
>
> Trevor
>
>

Trevor Southam

unread,
Jul 22, 2000, 3:00:00 AM7/22/00
to
Alan
What I want to save is the colour of the cell along with the text in it. The object
is a pointer to say clBlue or clRed for example. I expect this makes the problem
worse.

Trevor

AlanGLLoyd wrote:

> In article <3978AC3F...@starcomms.co.uk>, Trevor Southam
> <dev...@starcomms.co.uk> writes:
>

> >Does anyone know how to save StringGrid text and objects in cells to and
> >from a file. I have to save the grid on every change to a cell and
> >restore it in the event of a crash or power failure. I have got the text
> >part working (sort of) but not the objects.
> >I'm using Delphi 4.
> >
>

hotfix

unread,
Jul 22, 2000, 3:00:00 AM7/22/00
to
you'll just have to write a routine that saves your stuff to file
untested:
var f : textfile;
begin
assignfile(f,MyFile);
rewrite(f);
for nn := 0 to sg.cols.count -1 do begin
for nCount := 0 to sg.rows.count -1 do begin
writeln(f, sg.cells[nn,ncount];
writeln(f, integer(sg.objects[nN,nCount]));
end;
end;
closefile(f);

end;

method similar for other file types

sg.objects[0,0] := pointer(ord(clRed));
g := integer(sg.objects[0,0]);

Trevor Southam <dev...@starcomms.co.uk> wrote in message

news:3979681E...@starcomms.co.uk...

Trevor Southam

unread,
Jul 22, 2000, 3:00:00 AM7/22/00
to
Thanks for that I'll give it a try.

Trevor

Trevor Southam

unread,
Jul 22, 2000, 3:00:00 AM7/22/00
to
Cracked it :o)
I was so close that I couldn't see the answer.
The bit I missed was ... writeln(f, integer(sg.objects[nN,nCount]));
I had everything else.

Thanks for all the input guys.

AlanGLLoyd

unread,
Jul 22, 2000, 3:00:00 AM7/22/00
to
In article <3979681E...@starcomms.co.uk>, Trevor Southam
<dev...@starcomms.co.uk> writes:

>What I want to save is the colour of the cell along with the text in it. The
>object
>is a pointer to say clBlue or clRed for example. I expect this makes the
>problem
>worse.
>

Trevor

That's fairly easy, provided you've stored the color in the Objects as
TObject(clBlue) etc. Just remember that TStringGrid.Rows (and TStringGrid.Cols)
are a TStrings. You have to store the number of strings/objects before storing
the strings, and also the number of TStringGrid.Rows.

The following should do it - except for the Read/WriteStreamInt() &
Read/WriteStreamString(), I have only tested it for compile, but most of it is
straight-forward. It's split into a number of procedures for clarity and ease
of my writing, you would most likely put them all together as methods anyway.

function ReadStreamInt(Stream : TStream) : integer;
{returns an integer from stream}
begin
if Stream.Read(Result, SizeOf(Integer)) < SizeOf(Integer) then
Result := -1;
end;

function ReadStreamStr(Stream : TStream) : string;
{returns a string from the stream}
var
StrLen : integer;
begin
{get length of string}
StrLen := ReadStreamInt(Stream);
if StrLen > -1 then begin
{set string to get memory}
SetLength(Result, StrLen);
{read characters}
Stream.Read(Result[1], StrLen);
end
else
Result := '';
{end; if StrLen > -1 else}
end;

procedure WriteStreamInt(Stream : TStream; Num : integer);
{writes an integer to the stream}
begin
Stream.Write(Num, SizeOf(Integer));
end;

procedure WriteStreamStr(Stream : TStream; Str : string);
{writes a string to the stream}
var
StrLen : integer;
begin
{get length of string}
StrLen := Length(Str);
{write length of string}
WriteStreamInt(Stream, StrLen);
{write characters}
Stream.Write(Str[1], StrLen);
end;

procedure SaveStringsColorToStream(SL : TStrings; Stream : TStream);
{saves strings and color objects from TStringList to stream
stream must be positioned ready to receive the data,
and is left positioned after writing the data}
var
StrCount, i : integer;
CellColor : TColor;
begin
StrCount := SL.Count;
WriteStreamInt(Stream, StrCount);
for i := 0 to SL.Count - 1 do begin
WriteStreamStr(Stream, SL.Strings[i]);
CellColor := TColor(SL.Objects[i]);
WriteStreamInt(Stream, CellColor);
end;
end;

procedure LoadStringsColorFromStream(SL : TStrings; Stream : TStream);
{loads strings and color objects to a TStringList from a stream
stream must be positioned at start of appropriate data,
and is left positioned after the data}
var
StrCount, i : integer;
Str : string;
CellColor : TColor;
begin
StrCount := ReadStreamInt(Stream);
for i := 0 to StrCount - 1 do begin
Str := ReadStreamStr(Stream);
CellColor := TColor(ReadStreamInt(Stream));
SL.AddObject(Str, TObject(CellColor));
end;
end;

procedure SaveStringGridToStream(SG : TStringGrid; Stream : TStream);
{saves string grid cell contents and TColor objects to a stream}
var
RowCount, i : integer;
begin
Stream.Seek(0, soFromBeginning);
RowCount := SG.RowCount;
WriteStreamInt(Stream, RowCount);
for i := 0 to SG.RowCount - 1 do
SaveStringsColorToStream(SG.Rows[i], Stream);
end;

procedure LoadStringGridFromStream(SG : TStringGrid; Stream : TStream);
{loads stringgrid from a stream conttaining strings and Tcolor objects}
var
RowCount, i : integer;
SL : TStringList;
begin
Stream.Seek(0, soFromBeginning);
RowCount := ReadStreamInt(Stream);
SL := TStringList.Create;
if SG.RowCount <> RowCount then
SG.RowCount := RowCount;
for i := 0 to RowCount - 1 do begin
SL.Clear;
LoadStringsColorFromStream(SL, Stream);
SG.Rows[i].Assign(SL);
end;
SL.Free;
end;

procedure SaveStringGridToFile(SG : TStringGrid; FileName : string);
var
FS : TFileStream;
begin
FS := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
SaveStringGridToStream(SG, FS);
FS.Free;
end;

procedure LoadStringGridFromFile(SG : TStringGrid; FileName : string);
var
FS : TFileStream;
begin
FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
LoadStringGridFromStream(SG, FS);
FS.Free;
end;

Alan Lloyd
alang...@aol.com

AlanGLLoyd

unread,
Jul 23, 2000, 3:00:00 AM7/23/00
to
In article <3979681E...@starcomms.co.uk>, AlanGLLoyd writes:

>The following should do it -

Trevor

Whooopppsss - bit of brain GPF there.

The fact that you use the object value as a TColor has nothing to do with
saving and loading it to a stringgrid. And I did not restore the column count
of the stringgrid. Here is one I did later - and has been tested <gg>.

//= Save & Load StringGrid Strings and Object Integers ====

procedure SaveStringsObjectsToStream(SL : TStrings; Stream : TStream);
{saves strings and objects from TStringList to stream


stream must be positioned ready to receive the data,
and is left positioned after writing the data}

{Note :- Only the object value is saved, this is only meaningful if it has
been used as an integer value, as an object pointer it is meaningless}
var
StrCount, i, Obj : integer;


begin
StrCount := SL.Count;
WriteStreamInt(Stream, StrCount);
for i := 0 to SL.Count - 1 do begin
WriteStreamStr(Stream, SL.Strings[i]);

Obj := integer(SL.Objects[i]);
WriteStreamInt(Stream, Obj);
end;
end;

procedure LoadStringsObjectsFromStream(SL : TStrings; Stream : TStream);
{loads strings and objects to a TStringList from a stream


stream must be positioned at start of appropriate data,
and is left positioned after the data}

{Note :- Only the object value is loaded, this is only meaningful if it is
used as an integer value, as an object pointer it is meaningless}
var
StrCount, i, Obj : integer;
Str : string;


begin
StrCount := ReadStreamInt(Stream);
for i := 0 to StrCount - 1 do begin
Str := ReadStreamStr(Stream);

Obj := ReadStreamInt(Stream);
SL.AddObject(Str, TObject(Obj));
end;
end;

procedure SaveStringGridToStream(SG : TStringGrid; Stream : TStream);
{saves string grid cell contents and TColor objects to a stream}
var

ColCount, RowCount, i : integer;
begin
Stream.Seek(0, soFromBeginning);
ColCount := SG.ColCount;
WriteStreamInt(Stream, ColCount);


RowCount := SG.RowCount;
WriteStreamInt(Stream, RowCount);
for i := 0 to SG.RowCount - 1 do

SaveStringsObjectsToStream(SG.Rows[i], Stream);
end;

procedure LoadStringGridFromStream(SG : TStringGrid; Stream : TStream);

{loads stringgrid from a stream containing strings and Tcolor objects}
var
ColCount, RowCount, i : integer;


SL : TStringList;
begin
Stream.Seek(0, soFromBeginning);

ColCount := ReadStreamInt(Stream);
SG.ColCount := ColCount;
RowCount := ReadStreamInt(Stream);
SG.RowCount := RowCount;
SL := TStringList.Create;


for i := 0 to RowCount - 1 do begin
SL.Clear;

LoadStringsObjectsFromStream(SL, Stream);


SG.Rows[i].Assign(SL);
end;
SL.Free;
end;

procedure SaveStringGridToFile(SG : TStringGrid; FileName : string);
var
FS : TFileStream;
begin
FS := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
SaveStringGridToStream(SG, FS);
FS.Free;
end;

procedure LoadStringGridFromFile(SG : TStringGrid; FileName : string);
var
FS : TFileStream;
begin
FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
LoadStringGridFromStream(SG, FS);
FS.Free;
end;

//=========================================================

Alan Lloyd
alang...@aol.com

Trevor Southam

unread,
Jul 23, 2000, 3:00:00 AM7/23/00
to
Alan
Thanks for the code. I was given the following by Hotfix (earlier in this thread).

var f : textfile;
begin
assignfile(f,MyFile);
rewrite(f);
for nn := 0 to sg.cols.count -1 do begin
for nCount := 0 to sg.rows.count -1 do begin
writeln(f, sg.cells[nn,ncount];
writeln(f, integer(sg.objects[nN,nCount]));
end;
end;
closefile(f);

end;


This was close to what I was attempting to do and it works.
The question is ... which would be more robust yours or the above ?
You code looks more universal as to the types of objects being streamed (I think).
I'm no expert on this as the only streaming I've done has been text based.
I shall certainly go away and play with this to learn more about how it works.
Thanks again Alan

Trevor

VBDis

unread,
Jul 25, 2000, 3:00:00 AM7/25/00
to
Im Artikel <397ACA44...@starcomms.co.uk>, Trevor Southam
<dev...@starcomms.co.uk> schreibt:

>I'm no expert on this as the only streaming I've done has been text based.

Regardless of the storage format, you can wind up the problem from the opposite
side: how to restore an object from a stream? Then you'll find statements like:

//for each cell...
grid.Strings[x,y] := ReadTheString(stream);
ObjType := ReadTheObjType(stream);
if ObjType <> nil then begin
grid.Objects[x,y] := ObjType.Create;
grid.Objects[x,y].LoadFromStream(stream);
end;
//loop...

Saving the objects then will store the object type (class) and data in the same
way, as it's read back by the loading code later.

When all objects are of the same class, you can omit the step to store and read
the class type, and create objects of the predefined class. Likewise the
information for every object can be read by the appropriate statements, as the
information was stored in the stream before.

For more flexibility, create a base class for all intended objects, which
includes at least the SaveToStream and LoadFromStream methods. The creation of
the objects can be encapsulated in a class method CreateFromStream, which reads
the object type, creates the according object, calls it's LoadFromStream
method, and returns the new object.

In your case, the resulting base class could look like:

TStreamableObject = class
public
class function CreateFromStream(stream: TStream): TObject;
procedure LoadFromStream(stream: TStream); virtual; abstract;
procedure SaveToStream(stream: TStream); virtual; abstract;
...
end;

class function TStreamableObject.CreateFromStream;
var c: char;
begin
stream.Read(c, 1); //means: ReadTheObjectType
case c of
'c': //meaning a "color" object
stream.Read(Result, sizeof(TColor)); //very dirty!
'C': //requires a Class TColorObject(TStreamableObject)...
begin
Result := TColorObject.Create;
Result.LoadFromStream(stream);
//which does: stream.Read(self.Color, sizeof(self.Color));
end;
//more cases as required...
else
Result := nil;
end;
end;

TColorObject = class(TStreamableObject)
public
FColor: TColor;
procedure LoadFromStream(stream: TStream); override;
procedure SaveToStream(stream: TStream); override;
...
end;

procedure TColorObject.LoadFromStream;
begin
stream.Read(FColor, sizeof(FColor);
end;

procedure TColorObject.SaveToStream;
begin
//optionally: write a class type indicator
stream.Write('C', 1); //as appropriate
//mandatory: the data
stream.Write(FColor, sizeof(FColor));
//write more as appropriate for other objects...
end;

The write loop should write a predefined character to the stream for every Nil
object, so that the CreateFromStream can read a character (or integer or
whatsoever...) even for nonexisting objects. You also can substitute TStream by
a Text file, and read/write the information in the appropriate format, as you
used to do before.

It's up to you to keep in sync the writing and reading of any information in
the stream.

DoDi

Trevor Southam

unread,
Jul 26, 2000, 3:00:00 AM7/26/00
to
Hi DoDi
Thanks for you input to this thread, I have a nice pile of information to digest
and when the pressure is off me I'll be going through all of it to increase my
knowledge.
I have got the problem sorted at the moment but when I do my next update I will
revisit this subject and probably re-write it using a different method.
As I said earlier on in this thread it's nice to see how different people overcome
the same problem. I that way I and any others who are lurking can always learn
something new.

Regards
Trevor

VBDis wrote:

> Im Artikel <397ACA44...@starcomms.co.uk>, Trevor Southam
> <dev...@starcomms.co.uk> schreibt:
>

> >I'm no expert on this as the only streaming I've done has been text based.
>

0 new messages