Recent

Author Topic: save and restore a form for lazarus  (Read 6549 times)

nana232

  • New Member
  • *
  • Posts: 40
save and restore a form for lazarus
« on: March 18, 2017, 07:16:38 am »
I found the Delphi's method in Stackover flow from the following link:
http://stackoverflow.com/questions/3163586/how-to-save-and-restore-a-form


Quote
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:

Code: Pascal  [Select][+][-]
  1. procedure SaveComponentToFile(Component: TComponent; const FileName: TFileName);
  2. var
  3.   FileStream : TFileStream;
  4.   MemStream : TMemoryStream;
  5. begin
  6.   MemStream := nil;
  7.  
  8.   if not Assigned(Component) then
  9.     raise Exception.Create('Component is not assigned');
  10.  
  11.   FileStream := TFileStream.Create(FileName,fmCreate);
  12.   try
  13.     MemStream := TMemoryStream.Create;
  14.     MemStream.WriteComponent(Component);
  15.     MemStream.Position := 0;
  16.     ObjectBinaryToText(MemStream, FileStream);
  17.   finally
  18.     MemStream.Free;
  19.     FileStream.Free;
  20.   end;
  21. 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:

Code: Pascal  [Select][+][-]
  1. procedure LoadComponentFromFile(Component: TComponent; const FileName: TFileName);
  2. var
  3.   FileStream : TFileStream;
  4.   MemStream : TMemoryStream;
  5.   i: Integer;
  6. begin
  7.   MemStream := nil;
  8.  
  9.   if not Assigned(Component) then
  10.     raise Exception.Create('Component is not assigned');
  11.  
  12.   if FileExists(FileName) then
  13.   begin
  14.     FileStream := TFileStream.Create(FileName,fmOpenRead);
  15.     try
  16.       for i := Component.ComponentCount - 1 downto 0 do
  17.       begin
  18.         if Component.Components[i] is TControl then
  19.           TControl(Component.Components[i]).Parent := nil;
  20.         Component.Components[i].Free;
  21.       end;
  22.  
  23.       MemStream := TMemoryStream.Create;
  24.       ObjectTextToBinary(FileStream, MemStream);
  25.       MemStream.Position := 0;
  26.       MemStream.ReadComponent(Component);
  27.       Application.InsertComponent(Component);
  28.     finally
  29.       MemStream.Free;
  30.       FileStream.Free;
  31.     end;
  32.   end;
  33. end;
  34.  

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

Code: Pascal  [Select][+][-]
  1. 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:

Code: Pascal  [Select][+][-]
  1.   if not Assigned(FSecondForm) then
  2.     FSecondForm := TfrmSecond.Create(Application);
  3.   LoadComponentFromFile(FSecondForm,ExtractFilePath(Application.ExeName)+ 'formdata.txt');
  4.   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.


From ... vcldeveloper



I 've tried these codes in Lazarus with my simple Form:

[Form1 , Edit1,2,3 , and two buttons (SaveBtn aand LoadBtn)]

The app can save and load all components properly but still have Error of Duplicate Name ("Form1_1")
and External SIGSEGV.
The error may occur from the last two codes, because I replaced "FSecondForm" with" Form1"
and and "TfrmSecond" by "TForm1" as shown below:

Quote
Code: Pascal  [Select][+][-]
  1. SaveComponentToFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');


Code: Pascal  [Select][+][-]
  1.   if not Assigned(Form1) then
  2.     Form1 := TForm1.Create(Application);
  3.   LoadComponentFromFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');
  4.   Form1.Show;



Could anyone please tell me " How to modify these codes?".

Thank you
 
Lazarus 1.8.4 Win10 32bit

sky_khan

  • Guest
Re: save and restore a form for lazarus
« Reply #1 on: March 18, 2017, 09:06:54 am »
if Form1 is your Application's mainform, it is already assigned so you are running only these lines
Code: Pascal  [Select][+][-]
  1. LoadComponentFromFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');
  2. Form1.Show;
  3.  

therefore, as Form1 is already exists, you are trying to load its child components and insert into Application, again! No wonder it complain about duplicates.

What are you trying to accomplish ?

nana232

  • New Member
  • *
  • Posts: 40
Re: save and restore a form for lazarus
« Reply #2 on: March 18, 2017, 06:34:46 pm »
if Form1 is your Application's mainform, it is already assigned so you are running only these lines
Code: Pascal  [Select][+][-]
  1. LoadComponentFromFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');
  2. Form1.Show;
  3.  

therefore, as Form1 is already exists, you are trying to load its child components and insert into Application, again! No wonder it complain about duplicates.

What are you trying to accomplish ?

Actually, I would like to save all components and variables which are contained in MainForm.
Lazarus 1.8.4 Win10 32bit

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: save and restore a form for lazarus
« Reply #3 on: March 18, 2017, 09:10:08 pm »
Actually, I would like to save all components and variables which are contained in MainForm.

The IDE does this for you.
The mainform.lfm saves a text representation of the main TForm class descendant, and a text representation of all the controls it contains.
The variables are all named in the main form's .pas (or .pp) file. You could parse this to look for, say, just the global variables (if that is what you are after).
However, getting the variables' values would be trickier. Being variable, the values ... vary. So if you are after variable value data you'll have to be more specific about at what point in the app's lifecycle you wanted the variables' values, and if you wanted only the values of simple variables, or also values of records, arrays, and non-GUI classes etc.

Saving this data is fairly straightforward, as the code you showed indicates. But the IDE does a perfect job of completing this task, so I don't see the point of reinventing that wheel.

On the other hand the code you show for reconstructing a form and its components is nonsense. On the pretext of avoiding name clashes the code tries to strip out all the form's contents.
What good is a reconstructed empty form? You might just as well call Application.CreateForm(xx, yy); and be done with it.
Presumably the point of the code you found was to save and later rebuild an entire form. This is a non-trivial exercise, and the IDE Designer devotes hundreds if not thousands of lines to this task, since this is exactly what the IDE has to do when it opens a GUI project. Don't imagine that it is a ten-liner to rebuild a form from its .pas and .lfm files and recursively construct each control and any sub controls and get them all parented properly after finding all the required registered classes.

nana232

  • New Member
  • *
  • Posts: 40
Re: save and restore a form for lazarus
« Reply #4 on: March 20, 2017, 07:51:55 am »
Thanks for all answers.
 :)
Lazarus 1.8.4 Win10 32bit

sky_khan

  • Guest
Re: save and restore a form for lazarus
« Reply #5 on: March 20, 2017, 12:18:18 pm »
Using component streaming to save data is kind of messy and not reliable in long term. Classes and properties change by every version of Lazarus etc.

If you're trying to save form properties you may use FormStorage components like TXMLPropStorage or TIniPropStorage. They're on Misc tab.

e.g: Put a TXMLPropStorage on your form and use your Form's SessionProperties property to save properties you want to keep between sessions of your program

http://wiki.freepascal.org/TXMLPropStorage

LBoxPO

  • New Member
  • *
  • Posts: 15
Re: save and restore a form for lazarus
« Reply #6 on: September 06, 2024, 05:28:56 pm »
Hello everyone  :)

This is exactly the topic that interests me now, but when I create a simple application
and add these procedures to the code, an error occurs when running, which you can see in the screenshot.

Lazarus experts, please help me understand what is the cause of these errors  :(

Here is the entire code
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     procedure SaveComponentToFile(Component: TComponent; const FileName: TFileName);
  16.     procedure LoadComponentFromFile(Component: TComponent; const FileName: TFileName);
  17.   private
  18.  
  19.   public
  20.  
  21.   end;
  22.  
  23. var
  24.   Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TForm1 }
  31.  
  32. procedure SaveComponentToFile(Component: TComponent; const FileName: TFileName);
  33. var
  34.   FileStream : TFileStream;
  35.   MemStream : TMemoryStream;
  36. begin
  37.   MemStream := nil;
  38.  
  39.   if not Assigned(Component) then
  40.     raise Exception.Create('Component is not assigned');
  41.  
  42.   FileStream := TFileStream.Create(FileName,fmCreate);
  43.   try
  44.     MemStream := TMemoryStream.Create;
  45.     MemStream.WriteComponent(Component);
  46.     MemStream.Position := 0;
  47.     ObjectBinaryToText(MemStream, FileStream);
  48.   finally
  49.     MemStream.Free;
  50.     FileStream.Free;
  51.   end;
  52. end;
  53.  
  54. procedure LoadComponentFromFile(Component: TComponent; const FileName: TFileName);
  55. var
  56.   FileStream : TFileStream;
  57.   MemStream : TMemoryStream;
  58.   i: Integer;
  59. begin
  60.   MemStream := nil;
  61.  
  62.   if not Assigned(Component) then
  63.     raise Exception.Create('Component is not assigned');
  64.  
  65.   if FileExists(FileName) then
  66.   begin
  67.     FileStream := TFileStream.Create(FileName,fmOpenRead);
  68.     try
  69.       for i := Component.ComponentCount - 1 downto 0 do
  70.       begin
  71.         if Component.Components[i] is TControl then
  72.           TControl(Component.Components[i]).Parent := nil;
  73.         Component.Components[i].Free;
  74.       end;
  75.  
  76.       MemStream := TMemoryStream.Create;
  77.       ObjectTextToBinary(FileStream, MemStream);
  78.       MemStream.Position := 0;
  79.       MemStream.ReadComponent(Component);
  80.       Application.InsertComponent(Component);
  81.     finally
  82.       MemStream.Free;
  83.       FileStream.Free;
  84.     end;
  85.   end;
  86. end;
  87.  
  88. end.
  89.  

LBoxPO

  • New Member
  • *
  • Posts: 15
Re: save and restore a form for lazarus
« Reply #7 on: September 06, 2024, 06:13:28 pm »
I found the cause of the error 8)

At the beginning of the procedure description, before the procedure name, it was necessary to add "TForm1."

Now the program starts without errors. Let's see what happens next)
I hope the process of saving and loading components will go without errors

 

TinyPortal © 2005-2018