views:

168

answers:

4

So, I have a form with a few dozen controls and someone would like to save & later restore their contents & settings - which radio button was selected, what was the Position of that up/down, etc

What's the simplest way to do it? DfmToString & reverse? Write/read a .INI ? Something else?

+1  A: 

I typically store the values in the registry/.ini file.

However, I've used controls that you can drop on the form that store the state automatically. The one that I've used went out of business, so I can't recommend any, but take a look at a list.

Edit

I've found the one that I've used called oxPersist.

Marcus Adams
+1 Marcus, thanks for the help. IMO, the registry is *EVIL*, but INI is ok. The thing about the components that save themselves is that they are not a solution if I use non-standard components. So, it looks like INI then
Mawg
+8  A: 

@mawg, the JVCL Library comes with an set of components ( alt textTJvFormStorage, TJvAppXMLFileStorage, etc) to save and restore objects to xml files, the windows registry and ini files.

if you install the jedi components check the JvAppStoreDemo.dpr located in the jvcl\examples\JvAppStorage\Base Example folder.

RRUZ
+1 Sounds great. I'll check this out !
Mawg
+1  A: 

It is pretty easy to read/write component or object properties, or forms position in INI file or registry. Everything you need exist in help. You just need to decide when you want to read them (on creating, before showing...) and store them (on close, ...). This depends on what you are saving/restoring. If you are going to use ready made components and want to save form position, then make sure to check how do they treat multiple monitors. If you are doing it your own way, you should take care of that yourself. For example, you might have a laptop and a big 22" monitor, and position of a form was saved while your big monitor was used. Later, if you open this form on laptop it might be displayed of screen so you can not see the form if this case is not handled properly.

avra
+4  A: 

PRUZ's solution is a ready made solution; JVCL is open-source, and using JvFormStorage is simple. But you can also use Delphi's own streaming mechanism without using any third-party components. Here is an example:

procedure SaveComponentToFile(Component: TComponent; const FileName: TFileName);
var
  FileStream : TFileStream;
  MemStream : TMemoryStream;
begin
  MemStream := nil;

  if not Assigned(Component) then
    raise Exception.Create('Component is not assigned');

  FileStream := TFileStream.Create(FileName,fmCreate);
  try
    MemStream := TMemoryStream.Create;
    MemStream.WriteComponent(Component);
    MemStream.Position := 0;
    ObjectBinaryToText(MemStream, FileStream);
  finally
    MemStream.Free;
    FileStream.Free;
  end;
end;

SaveComponentToFile takes a component instance, plus a file name, and streams the component into the file, in a human-readable text.

To load the component from file, you can use a code like this:

procedure LoadComponentFromFile(Component: TComponent; const FileName: TFileName);
var
  FileStream : TFileStream;
  MemStream : TMemoryStream;
  i: Integer;
begin
  MemStream := nil;

  if not Assigned(Component) then
    raise Exception.Create('Component is not assigned');

  if FileExists(FileName) then
  begin
    FileStream := TFileStream.Create(FileName,fmOpenRead);
    try
      for i := Component.ComponentCount - 1 downto 0 do
      begin
        if Component.Components[i] is TControl then
          TControl(Component.Components[i]).Parent := nil;
        Component.Components[i].Free;
      end;

      MemStream := TMemoryStream.Create;
      ObjectTextToBinary(FileStream, MemStream);
      MemStream.Position := 0;
      MemStream.ReadComponent(Component);
      Application.InsertComponent(Component);
    finally
      MemStream.Free;
      FileStream.Free;
    end;
  end;
end;

LoadComponentFromFile takes a component instance, and a file name, then loads file content into the component instance. To avoid naming conflict, we are free all existing owned components of the instance, before loading file data into it.

Now you can use the above code for saving a form into a file:

  SaveComponentToFile(FSecondForm,ExtractFilePath(Application.ExeName)+ 'formdata.txt');

FSecondForm is a form instance, and it will be saved into "formdata.txt" file inside the same folder as the EXE file.

And to load FSecondForm from "formdata.txt" file, we write this:

  if not Assigned(FSecondForm) then
    FSecondForm := TfrmSecond.Create(Application);
  LoadComponentFromFile(FSecondForm,ExtractFilePath(Application.ExeName)+ 'formdata.txt');
  FSecondForm.Show;

LoadComponentFromFile needs the instance to be created first, so we check if FSecondForm is assigned, if not, we create an instance of it (it is an instance of TfrmSecond class), and then load file data into it. And eventually, we show the loaded form.

vcldeveloper