views:

673

answers:

3

How best could I save this component and all internal variables? Examples of code would be appreciated.

  TSmall = record
      fName: string[30];
      fAge: integer;
      fID_Number: string[30];
  end;

  TRec = record
    ArraySmall: array[1..10] of TSmall;
  end;

  TBigComponent = class(TComponent)
    private
      fSmallArr: TRec;
      fCompCount: integer;
      fBigName: string;
    public
      procedure AddNew(Name: string; Age: integer; ID: string);
      procedure Save(FileName: string);
      procedure Load(FileName: string);
      procedure SetName(Name: string);
      function GetName: string;
      function ToString: string;
    published
      property SmallArr: TRec read fSmallArr write fSmallArr;
      property Count: integer read fCompCount write fCompCount;
      property Name: string read fBigName write fBigName;
    end;
+1  A: 

To make use of Delphi internal persistence and RTTI you should use classes instead of records.

There are lots of good advice and examples here:

http://stackoverflow.com/questions/368913/whats-a-good-way-to-serialize-delphi-object-tree-to-xml-using-rtti-and-not-cust

If you are looking for an example of saving custom data to a visual component, check the Delphi VCL source for method TTreeNodes.DefineProperties in file ComCtrls.pas.

Ville Krumlinde
+1  A: 

In general, it's probably the easiest to follow VilleK's suggestion, and make use of what Tpersistent provides.

However, I somehow prefer this method, so I keep full control over the structure of the file.

type
  TFileStruct=packed record
    fSmallArr: TRec;
    fCompCount: UINT32; // be explicit.. who knows what 64bit Delphi does to your integers...
    fBigName: String[250]; // AnsiChar
  end;

procedure TBigComponent.Save(FileName: string);
var
  F:File of TFileStruct;
  FileStruct:TFileStruct;
begin
  FileStruct.fSmallArr := fSmallArr;
  FileStruct.fCompCount := fCompCount;
  FileStruct.fBigName := fBigName;

  AssignFile(F,FileName);
  Rewrite(F);
  Write(F,FileStruct);
  CloseFile(F);
end;

Keep in mind that String[xxx] seems to be treated like AnsiString, so if you use Delphi 2009, your Unicode strings will be changed into AnsiStrings when you save. At least files will be exchangable with software that's compiled with older versions of Delphi.

In TSmall I'd change the integer for Age to Byte, so that you won't get in trouble with 64bit Delphi.
"8 bits should be enough for everyone" (c) 2009 Wouter :-)

Wouter van Nifterick
(off topic) According to David I Integer will remain 32 bit
Gerry
+1  A: 

A small enhancement to Wouter's suggestion:

 type
  TSmall = record
      fName: string[30];
      fAge: integer;
      fID_Number: string[30];
  end;

  TRec = record
    ArraySmall: array[1..10] of TSmall;
  end;

  TBigComponent = class(TComponent)
  private
      type
        TInternalFields = record
          SmallArr: TRec;
          CompCount: integer;
          BigName: Shortstring;
       end;
    var
      FFields : TInternalFields;
    public
      procedure AddNew(Name: string; Age: integer; ID: string);
      procedure Save(FileName: string);
      procedure Load(FileName: string);
      procedure SetName(Name: string);reintroduce;
      function GetName: string;
      function ToString: string;
    published
      property SmallArr: TRec read FFields.SmallArr write FFields.SmallArr;
      property Count: integer read FFields.CompCount write FFields.CompCount;
      property Name: ShortString read FFields.BigName write FFields.BigName;
    end;

procedure TBigComponent.Save(FileName: string);
var
  F:File of TInternalFields;
begin
  AssignFile(F,FileName);
  Rewrite(F);
  Write(F, FFields);
  CloseFile(F);
end;

This removes the need to copy each field from the object into a record - it is already in a record.

I'm not sure when the read Record.field syntax was added - it is in 2006

Gerry
Thanks for pointing that out - I had no idea abut the read Record.field syntax.
robsoft