Search code examples
delphi

How to save and restore a form?


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

I would also like to store any entries added to a list box at run time.

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


Solution

  • 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.