Link to home
Start Free TrialLog in
Avatar of JustinCase
JustinCase

asked on

Saving a fonts properties

Hi,

I have a record the among other contains a font.

TRecType = record
  ...
  font : TFont;
end;

I'm trying to save the TRecType in a filestream, but when I reload it none of the font properties are restored.

My code look something like this :

Saving :
---
Rec : TRecType;
F : TFileStream.Create( 'filename', fmOpenWrite );
F.write( Rec, SizeOf(Rec) );
F.Destroy;
---

And when I reload the record :
---
Rec : TRecType;
Rec.Font.create;
F : TFileStream.Create( 'filename', fmOpenRead );
F.read( Rec, SizeOf(Rec) );
F.Destroy;
---

Howcome the font props are not loaded, and how can I do this.

Regards,

Johnny
Avatar of Igor UL7AAjr
Igor UL7AAjr
Flag of Kazakhstan image

Hi JustinCase,

"Howcome the font props are not loaded" - because you saved memory address where Font located instead of it's property.

Can you be more specific? How Rec.Font created? It's important to know to save and load font properly.

------
Igor.
Avatar of JustinCase
JustinCase

ASKER

Well, the record is declared somewhat as above (though the record contains other records. As this :

TRecType1 = record
  ... (ints and strings)
  font : TFont;
end;
 

TRecType2 = record
  ... (ints and strings)
  props : TRectType1;
end;

--------


In my units private interface I have declared

Setup : TRecType2;


In my Forms OnCreate Event I initialize as this :

Setup.props.font := TFont.Create;

-----------

And when assigning style and color to Setup.props.font I use a TFontDialog and assign like this :

Setup.props.font := FormDialog.Font;

-----------

Is this enough info ? I'll gladly provide more, but I do not know what. I've never worked with streams before.

/Johnny

Oh, I should properpluy mention that I save as the record like this :

F.Write( Setup, SizeOf(Setup) );
Hi JustinCase,

I think that way you use to store your data is not good enought. First of all it would be good to convert your record to class and write somemethods to store and load from/to stream.

Anyway, you should store members of your record one by one, otherwise you can override font address.

Here is sample how to write/read font's properties to/from stream:


type
   //  class to access protected TWriter.WriteProperties method
 TXWriter = class(TWriter)
 end;

  // class to access protected TReader.ReadProperty method
 TXReader = class(TReader)
 end;

// write Font's properties to the stream
procedure WriteFontToStream(Font: TFont; Stream: TStream);
var
  Writer: TXWriter;
begin
  Writer := TXWriter.Create(Stream, 1024);
  Writer.WriteListBegin;
  Writer.WriteProperties(Font);
  Writer.WriteListEnd;
  Writer.Free;
end;


// read Font's properties from stream
// Font must be created before!!!
procedure ReadFontFromStream(Font: TFont; Stream: TStream);
var
  Reader: TXReader;
begin
  Reader := TXReader.Create(Stream, 1024);
  Reader.ReadListBegin;
  try
    while not Reader.EndOfList do
      Reader.ReadProperty(Font);
    Reader.ReadListEnd;
  finally
    Reader.Free;
  end;
end;

------
Igor.
Thanks Igor,

I did not know of the TWriter/reader classes. I'll read up on it today, and then I'll properply have some questions to your example when I test it.

Thanks,
/Johnny
OK.

But there may be problem. WriteProperties method doesn't saves property that has default for component value. So, only modifyed values are stored and loaded. Let say if your Font.Color property = clWindowText then it will not be stored. As result it will not restore Font.Color property changed by user to clRed. To avoid of this situation it is necessary to store/load all properties. Seems you have to write your own mechanism to store/load properties.

------
Igor
Hi Igor,

Honestly I cannot find head nor tail in this.

TWriter does not have a WriteProperties method. (I use Delphi4) It does however have a WriteProperty method. But the method looks like this :
WriteProperty( Instance: TPersistent; PropInfo: TPointer);
I do not know how to assign this pointer to the the font properties and WritePropery is not documented in the helpfile. But this should not be a lesson in pointers.

I found something else though.

If I create a TXFont class, I can assign a TFiler and read/write through it.

From the helpfile :
"Provides an interface for a method that reads and writes otherwise unpublished data."


I did like this :
TXFont = class( TFont )
end;

Font := TXFont.Create;
Font.Assign( Setup.props.Font );
Font.DefineProperties( Writer );

But I cannot figure out how to get the writer to read and write the data.

Am I on the wrong track here ?? This is very much unchartered waters for me.
ASKER CERTIFIED SOLUTION
Avatar of Igor UL7AAjr
Igor UL7AAjr
Flag of Kazakhstan image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks,

I still want to understand though.

Can you suggest any reading ? Or maybe a tutorial link or the like.

Again thanks for the help,
Johnny
Hi Johny,

thanx for the points with "A" grade.

reading....
to tell you trust I prefer to explore VCL source code. Most of my knowelege is from there. Really :-)

Regards,
Igor.

PS: if you have some question, then you can ask me here or directly  igor@novell.kz