Forum > General

save and restore a form for lazarus

(1/2) > >>

nana232:
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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---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:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---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


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  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.


From ... vcldeveloper


--- End quote ---


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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---SaveComponentToFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  if not Assigned(Form1) then    Form1 := TForm1.Create(Application);  LoadComponentFromFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');  Form1.Show;

--- End quote ---


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

Thank you
 

sky_khan:
if Form1 is your Application's mainform, it is already assigned so you are running only these lines

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---LoadComponentFromFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');Form1.Show; 
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:

--- Quote from: SkyKhan 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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---LoadComponentFromFile(Form1,ExtractFilePath(Application.ExeName)+ 'formdata.txt');Form1.Show; 
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 ?

--- End quote ---

Actually, I would like to save all components and variables which are contained in MainForm.

howardpc:

--- Quote from: nana232 on March 18, 2017, 06:34:46 pm ---Actually, I would like to save all components and variables which are contained in MainForm.

--- End quote ---

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:
Thanks for all answers.
 :)

Navigation

[0] Message Index

[#] Next page

Go to full version