8

This question seems easy but for some reason I have trouble finding the answer.

I have an application that saves the form's size and position on an INI file. That's all an well, however when you close the application when maximized it will save the size and position of the form maximized but not its state.

What I mean is that on the next run the form would appear maximized when in fact it's "restored" but covering the whole desktop.

Is there a way to save the form size previous to the maximize event, then save the fact that the form is maximized. The on the read from the INI file create the form in a maximized state and set its "restore" size to the one before the maximize event?

thanks!

5 Answers 5

12

Use the Windows API function GetWindowPlacement(), like so:

procedure TForm1.WriteSettings(AUserSettings: TIniFile);
var
  Wp: TWindowPlacement;
begin
  Assert(AUserSettings <> nil);

  if HandleAllocated then begin
    // The address of Wp should be used when function is called
    Wp.length := SizeOf(TWindowPlacement);
    GetWindowPlacement(Handle, @Wp);

    AUserSettings.WriteInteger(SektionMainForm, KeyFormLeft,
      Wp.rcNormalPosition.Left);
    AUserSettings.WriteInteger(SektionMainForm, KeyFormTop,
      Wp.rcNormalPosition.Top);
    AUserSettings.WriteInteger(SektionMainForm, KeyFormWidth,
      Wp.rcNormalPosition.Right - Wp.rcNormalPosition.Left);
    AUserSettings.WriteInteger(SektionMainForm, KeyFormHeight,
      Wp.rcNormalPosition.Bottom - Wp.rcNormalPosition.Top);
    AUserSettings.WriteBool(SektionMainForm, KeyFormMaximized,
      WindowState = wsMaximized);
  end;
end;
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks. How do I call this function? What is IPersistentSettingsWriter?
@wonderer -- This example shows usage example of the GetWindowPlacement API function. You would have to modify this example for your own project... and change the AUserSettings calls to something like an INI file, or user registry settings.
@skamradt: Indeed, +1. I just copied it from my current project. @wonderer: IPersistentSettingsWriter is in its simplest form a wrapper for TIniFile, you can see that the WriteXXX() methods have the same name and parameters. Simply replace as skamradt suggested.
Edited, hopefully it's clearer now. In my defense, I consider programming against interfaces instead of classes a very good thing. My settings interface can easily be implemented in terms of INI file, registry or even database table storage, and the code using it doesn't have to be changed one bit. Also, I have distinct IPersistentSettingsReader and IPersistentSettingsWriter interfaces, so it's impossible to accidently write to an INI file that is in a read-only directory if the code is given only a reader interface.
I understand, thank you. I get the following error: [Error] main.pas(1150): Incompatible types: 'tagWINDOWPLACEMENT' and 'PWindowPlacement' on GetWindowPlacement(Handle, Wp);
3

Try the Form.WindowState property. By reading this, you can write it to the ini file, then read back from the ini to re-set the state in the form.show method. You might want to re-cast it to an integer as the WindowState is an enumerated type (TWindowState).

Comments

3

Tom's answer should work nicely. Here is some Pseudo-Code to clarify a little:

procedure TfrmDatenMonitor.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  inherited;
  //*** Save the WindowState in every case
  aIniFile.WriteInteger(Name, 'State', Integer(WindowState));

  if WindowState = wsNormal then begin
    //*** Save Position and Size, too...
    aIniFile.WriteInteger(Name, 'Top',    Top);
    aIniFile.WriteInteger(Name, 'Left',   Left);
    aIniFile.WriteInteger(Name, 'Height', Height);
    aIniFile.WriteInteger(Name, 'Width',  Width);
  end;
end;

when reading the settings set Size and Position first. Then read the WindowState and assign it with a typecast:

WindowState := TWindowState(aIniFile.ReadInteger(Name, 'State', Integer(wsNormal)));

Comments

0

DelphiDabbler has some nice window state components. You just drop one on your form and it will save the state to an ini file or the registry on form destroy and load it on form create.

Comments

0

Updated to show a Delphi 11 solution.

See Embarcadero dockwiki https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Using_TIniFile_and_TMemIniFile

FMX Code:

uses System.IniFiles;

procedure TForm1.FormCreate(Sender: TObject);
var
  Ini : TIniFile;
begin
  Ini := TIniFile.Create( ChangeFileExt( ParamStr(0),'.ini' ));
  try
    if Ini.ReadBool( 'Form', 'InitMax', false ) then
      WindowState := TWindowState.wsMaximized
    else
      WindowState := TWindowState.wsNormal;
  finally
  end;
  Ini.Free;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  Ini : TIniFile;
begin
  Ini := TIniFile.Create( ChangeFileExt( ParamStr(0),'.ini' ));
  try
    Ini.WriteBool( 'Form', 'InitMax', WindowState = TWindowState.wsMaximized );
  finally
    Ini.Free;
  end;
end;

3 Comments

I can't see how that answers the original question or improves on the existing answers.
OP said "This question seems easy but for some reason I have trouble finding the answer." The OP asked this question 13 years ago. Embarcadero has since provided an "easy to find" answer. I'd say that's an improvement.
But it doesn't store form size as OP requested. That's straightforward to add, but another problem is that if the form is maximised, it doesn't save the restored position, width and height.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.