Peter Martin's Delphi Tips

Remember your Application's Form States across Sessions

A good user-interface will remember things for users, so that they don't have to carry out the same operations over and over again. 

The most basic example of this is to remember your main form's size and position on the screen at the end of each session, and to restore it automatically at the beginning of the next session. The PutIniFormSettings and GetIniFormSettings procedures below can be used to save and restore any form's settings in an INI file. 

If you main form is a dialog full of controls, you can use the PutIniControlSettings and GetIniControlSettings procedures below to remember the control settings or contents, as appropriate; and restore it all at the start of the next session. 

If your main form is a document window, you could instead remember the last-used document filename, and re-open it automatically at the start of the next session. 

With these simple steps, exiting and re-launching your application can look no different from minimizing it and restoring it. 

See also the use of a most-recently used (MRU) menu.

unit uFormsToIni;

interface

uses
  SysUtils, Forms, Classes;

var
  IniFileName : string;

procedure GetIniFormSettings    (F : TForm);
procedure PutIniFormSettings    (F : TForm);
procedure GetIniControlSettings (F : TForm);
procedure PutIniControlSettings (F : TForm);

implementation

uses
  Spin, Mask, ExtCtrls, StdCtrls, Controls, IniFiles, Registry, Windows;

procedure GetIniFormSettings (F : TForm);
  // load form F's settings from INI file section with F's name
begin
  with TExIniFile.Create(IniFileName) do
    try
      F.WindowState:= TWindowState(ReadInteger(F.Name, 'State', ord(wsNormal)));
      if F.WindowState = wsNormal then begin
        F.Left:= ReadInteger(F.Name, 'Left', F.Left);
        F.Top:= ReadInteger(F.Name, 'Top', F.Top);
        if F.BorderStyle = bsSizeable then begin
          F.Width:= ReadInteger(F.Name, 'Width', F.Width);
          F.Height:= ReadInteger(F.Name, 'Height', F.Height);
          end;
      end;
    finally
      Free;
      end;
end;

procedure PutIniFormSettings (F : TForm);
  // save form F's settings to INI file section with F's name }
begin
  with TExIniFile.Create(IniFileName) do
    try
      WriteInteger(F.Name, 'State', ord(F.WindowState));
      if F.WindowState = wsNormal then begin
        WriteInteger(F.Name, 'Left', F.Left);
        WriteInteger(F.Name, 'Top', F.Top);
        if F.BorderStyle = bsSizeable then begin
          WriteInteger(F.Name, 'Width', F.Width);
          WriteInteger(F.Name, 'Height', F.Height);
          end;
        end;
    finally
      Free;
      end;
end;

procedure GetIniControlSettings (F : TForm);
  // load form F's control settings from INI file section with F's name
var
  IniFile : TExIniFile;

  procedure LoadWinControl (C : TWinControl);
  var
    I : integer;
  begin
    with C, IniFile do
      if ControlCount > 0 then
        for I:= 0 to ControlCount - 1 do
          if Controls[I] is TListBox then
            with Controls[I] as TListBox do
              ItemIndex:= ReadInteger(F.Name, Name, ItemIndex)
          else if Controls[I] is TComboBox then
            with Controls[I] as TCombobox do
              if Style = csDropDown then begin
                Items.CommaText:= ReadString(F.Name, Name + '_list',
                Items.CommaText);
                Text:= ReadString(F.Name, Name, Text);
                end
              else
                ItemIndex:= ReadInteger(F.Name, Name, ItemIndex)
          else if Controls[I] is TEdit then
            with Controls[I] as TEdit do
              Text:= ReadString(F.Name, Name, Text)
          else if Controls[I] is TMaskEdit then
            with Controls[I] as TMaskEdit do
              Text:= ReadString(F.Name, Name, Text)
          else if Controls[I] is TSpinEdit then
            with Controls[I] as TSpinEdit do
              Value:= ReadInteger(F.Name, Name, Value)
          else if Controls[I] is TCheckBox then
            with Controls[I] as TCheckBox do
              Checked:= ReadBool(F.Name, Name, Checked)
          else if Controls[I] is TRadioButton then
            with Controls[I] as TRadioButton do
              Checked:= ReadBool(F.Name, Name, Checked)
          else if Controls[I] is TRadioGroup then
            with Controls[I] as TRadioGroup do
              ItemIndex:= ReadInteger(F.Name, Name, ItemIndex)
          else if (Controls[I] is TGroupBox) or (Controls[I] is TPanel) or
              (Controls[I] is TScrollBox) then
            // recurse to child controls
            LoadWinControl(Controls[I] as TWinControl);
  end;  

begin // GetIniControlSettings
  IniFile:= TExIniFile.Create(IniFileName);
  try
    LoadWinControl(F as TWinControl);
  finally
    IniFile.Free;
    end;
end;

procedure PutIniControlSettings (F : TForm);
  // save form F's control settings to INI file section with F's name
var
  IniFile : TExIniFile;

  procedure SaveWinControl (C : TWinControl);
  var
    I : integer;
  begin
    with C, IniFile do
      if ControlCount > 0 then
        for I:= 0 to ControlCount - 1 do
          if Controls[I] is TListBox then
            with Controls[I] as TListBox do
              WriteInteger(F.Name, Name, ItemIndex)
          else if Controls[I] is TComboBox then
            with Controls[I] as TCombobox do
              if Style = csDropDown then begin
                WriteString(F.Name, Name + '_list', Items.CommaText);
                WriteString(F.Name, Name, Text);
                end
              else
                WriteInteger(F.Name, Name, ItemIndex)
          else if Controls[I] is TEdit then
            with Controls[I] as TEdit do
              WriteString(F.Name, Name, Text)
          else if Controls[I] is TMaskEdit then
            with Controls[I] as TMaskEdit do
              WriteString(F.Name, Name, Text)
          else if Controls[I] is TSpinEdit then
            with Controls[I] as TSpinEdit do
              WriteInteger(F.Name, Name, Value)
          else if Controls[I] is TCheckBox then
            with Controls[I] as TCheckBox do
              WriteBool(F.Name, Name, Checked)
          else if Controls[I] is TRadioButton then
            with Controls[I] as TRadioButton do
              WriteBool(F.Name, Name, Checked)
          else if Controls[I] is TRadioGroup then
            with Controls[I] as TRadioGroup do
              WriteInteger(F.Name, Name, ItemIndex)
          else if (Controls[I] is TGroupBox) or (Controls[I] is TPanel) or
              (Controls[I] is TScrollBox) then
            SaveWinControl(Controls[I] as TWinControl);
  end;

begin // PutIniControlSettings
  IniFile:= TIniFile.Create(IniFileName);
  with IniFile do
    try
      SaveWinControl(F as TWinControl);
    finally
      Free;
      end;
end;

initialization
  IniFileName:= ChangeFileExt(Application.EXEName, '.ini');

end.