在Delphi中如何保存窗体的最大化和大小设置?

8
这个问题看起来很简单,但出于某种原因,我在寻找答案时遇到了麻烦。
我有一个应用程序,它将表单的大小和位置保存在INI文件中。这一切都很好,但是当你关闭最大化的应用程序时,它会保存表单最大化的大小和位置,但不会保存其状态。
我的意思是,在下一次运行时,表单会显示为最大化,实际上它是“恢复”,但覆盖整个桌面。
是否有一种方法可以保存最大化事件之前的表单大小,然后保存表单已最大化的事实。在从INI文件读取时,创建一个最大化状态的表单,并将其“恢复”大小设置为最大化事件之前的大小?
谢谢!
5个回答

12

可以使用Windows API函数GetWindowPlacement(),如下所示:

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;

谢谢。我该如何调用这个函数?IPersistentSettingsWriter是什么? - wonderer
1
@wonderer -- 这个例子展示了如何使用GetWindowPlacement API函数。你需要根据自己的项目修改这个例子...并将AUserSettings调用更改为类似于INI文件或用户注册表设置的内容。 - skamradt
@skamradt:确实,+1。我只是从我的当前项目中复制了它。@wonderer:IPersistentSettingsWriter在其最简单的形式中是TIniFile的包装器,你可以看到WriteXXX()方法具有相同的名称和参数。按照skamradt的建议进行替换即可。 - mghie
编辑后,希望现在更清晰了。为自己辩护,我认为针对接口而不是类进行编程是一件非常好的事情。我的设置界面可以轻松地实现INI文件、注册表甚至数据库表存储,并且使用它的代码不需要改变一点。此外,我有独立的IPersistentSettingsReaderIPersistentSettingsWriter接口,因此如果代码只给出读取器接口,就不可能意外地写入只读目录中的INI文件。 - mghie
我明白了,谢谢。 我遇到了以下错误:[Error] main.pas(1150): 不兼容的类型:'tagWINDOWPLACEMENT' 和 'PWindowPlacement'在GetWindowPlacement(Handle, Wp); - wonderer

3

Tom的答案应该很好用。这里是一些伪代码,以便更清楚地说明:

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;

阅读设置时,请先设置“大小和位置”。 然后阅读“WindowState”,并使用类型转换进行分配:

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

3
尝试使用Form.WindowState属性。通过阅读此内容,您可以将其写入ini文件中,然后从ini中读取以重新设置表单显示方法中的状态。您可能需要将其重新转换为整数,因为WindowState是一个枚举类型(TWindowState)。

0
DelphiDabbler有一些很好的窗口状态组件。你只需要将其拖放到表单上,它就会在表单销毁时将状态保存到ini文件或注册表中,并在表单创建时加载它。

-1

已更新以展示 Delphi 11 解决方案。

请参见 Embarcadero dockwiki https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Using_TIniFile_and_TMemIniFile

FMX 代码:

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;

我看不出那如何回答原问题或改进现有答案。 - dummzeuch
OP说:“这个问题看起来很简单,但出于某些原因我找不到答案。” OP在13年前提出了这个问题。Embarcadero现已提供了一个“易于找到”的答案。我认为这是一种改进。 - Michael Riley - AKA Gunny
但它不会像 OP 请求的那样存储表单大小。这很容易添加,但另一个问题是,如果窗体被最大化,它不会保存恢复后的位置、宽度和高度。 - XylemFlow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接