Save Form Properties in File and then restore those Properties after reopening

105 views Asked by At

I am currently an apprentice and pretty new to Delphi, so I apologize if there is something obvious I'm missing. And I have to note I have to work with a 22 years old legacy code with approx 600k lines so that could be an error factor as well :D

I was tasked to code a way to save all currently open Forms with their properties like size, position, and window state and then restoring it after reopening the program. For that I decided to add in the FormCloseQuery in the Main Form a procedure which goes through all forms and writes their data (if Visible true) in a .ini file. Works pretty great so far and this is how it looks like:

procedure SaveFormInformation();
var
  i : Integer;
  form : TForm;
  iniFile : TIniFile;
begin
  iniFile := TIniFile.Create(ExtractFilePath(Application.ExeName) + 'FormInfo.ini');
  try
    for i := 0 to Screen.FormCount - 1 do
    begin
      form := Screen.Forms[i];
      if form.Visible then
      begin
        iniFile.WriteInteger(form.Name, 'Width', form.Width);
        iniFile.WriteInteger(form.Name, 'Height', form.Height);
        iniFile.WriteInteger(form.Name, 'Left', form.Left);
        iniFile.WriteInteger(form.Name, 'Top', form.Top);
        iniFile.WriteBool(form.Name, 'Visible', form.Visible);
        iniFile.WriteBool(form.Name, 'IsMaximized', form.WindowState = wsMaximized)
      end;
    end;
  finally
    iniFile.Free;
  end;
end;

And in the end, the .ini File it looks like this:

[F_Main]
Width=719
Height=542
Left=600
Top=305
Visible=1
IsMaximized=0
[F_PartList]
Width=1126
Height=716
Left=71
Top=301
Visible=1
IsMaximized=0

Now to my problem... the restoring. At first, I tried the same way with Screen.FormCount and, if Visible, read the .ini file and replace the values. That only worked partially because we have so many forms (masks), we decided to not initialize some forms in the beginning because of performance.

Then I decided to turn things around and include a loop which reads the .ini and only changes what's written there. But before it changes the properties, it looks if the form exists in the first place and creates it when not there. This part does not work the way i intend it to. The if statement - lookup works:

if Application.FindComponent(Sections[i]) as TForm = nil then

But the Application.CreateForm() doesn't. It seems like it cannot find the classes with their respective names alone. Thankfully we have a naming convention here so every TForm starts with F_ and every TFormClass with TF_ so it should theoretically be possible.

Here is the procedure of RestoreForms():

procedure RestoreForms();
var
  i : Integer;
  iniFile : TIniFile;
  form : TForm;
  FormClass : TFormClass;
  Sections : TStringList;
begin
  iniFile := TIniFile.Create(ExtractFilePath(Application.ExeName) + 'FormInfo.ini');
  Sections := TStringList.Create;

  try
    IniFile.ReadSections(Sections);
    for i := 0 to Sections.Count -1 do
    begin

      {form := Application.FindComponent(Sections[i]) as TForm;
      if not Assigned(form) then
      begin
        FormClass := TFormClass(GetClass('T' + Sections[i]));
        Application.CreateForm(FormClass, form);
        form.Free;
      end;}

      //Since not all Forms are initialized in the beginning this bit
      //does it for you. If the Form is nil then create Form
      if Application.FindComponent(Sections[i]) as TForm = nil then
      begin
        //FormClass := TFormClass(FindClass('T' + Sections[i]));
        FormClass := TFormClass(GetClass('T' + Sections[i]));
        form := Application.FindComponent(Sections[i]) as TForm;
        Application.CreateForm(FormClass, form);
        form.Free;
      end;

      //this puts the current read form of the ini File in a TForm Object
      //to then change its properties
      form := Application.FindComponent(Sections[i]) as TForm;
      with form do
      begin
        form.Top := IniFile.ReadInteger(form.Name, 'Top', Top);
        form.Left := IniFile.ReadInteger(form.Name, 'Left', Left);
        form.Height := IniFile.ReadInteger(form.Name, 'Height', Height);
        form.Width := IniFile.ReadInteger(form.Name, 'Width', Width);
        if iniFile.ReadBool(form.Name, 'IsMaximized', WindowState = wsMaximized) then
          form.WindowState := wsMaximized
        else
          form.WindowState := wsNormal;
        form.Position := poDesigned;
        if not (Sections[i] = 'F_Main') then
          form.Visible := IniFile.ReadBool(form.Name, 'Visible', Visible);
      end;
    end;
  finally
    Sections.Free;
    form.Free;
    iniFile.Free;
  end;
end;

Currently, the code "opens" the program but no Form will be seen. Only Services in Task manager can free me of the process ^^"

I also thought about saving their Window States of all open Forms in their respective FormClass itself, but since we have like 1k forms, it makes this task close to impossible.

I hope you guys can give me some pointers or ideas since neither google nor Stack Overflow nor AI could give me any answers as of now.

0

There are 0 answers