首页  编辑  

自动保存窗口状态的控件

Tags: /超级猛料/VCL/Form,窗体/   Date Created:

一些比较专业的软件都有自动保存窗口运行状态的功能,具体的方法都是在窗口关闭前将其状态保存到注册表中或ini文件中,而这些代码一般都是相同的,所以可以将其集中在一起,重复使用。本文将相应的代码用一个控件TPosition来实现,使用时只要将此控件放到相应的Form上即可,不需要增加任何代码,从而实现了"零"代码保存窗口运行状态。

  下面是这个控件的主要实现文件Position.pas的内容,包括相应的注释。为了保持注册表的整洁,这里把信息保存到ini文件中。

  unit Position;

  interface

  uses

  Forms, Classes, SysUtils, Windows, IniFiles;

  type

  //TPosition是不可视控件,由TComponent继承

  TPosition = class(TComponent)

  private

  //用此变量保存父窗口的OnDestroy事件

  FOnDestroy: TNotifyEvent;

  //用此函数替换父窗口的OnDestroy事件

  procedure FormDestroy(Sender: TObject);

  protected

  //在控件加载时恢复父窗口状态

  procedure Loaded; override;

  end;

  //恢复窗口位置函数

  procedure ReadFormPos(Form:TForm);

  //保存窗口位置函数

  procedure SaveFormPos(Form:TForm);

  //控件注册函数

  procedure Register;

  implementation

  //连接此控件的图标

  {$R Position.Dcr}

  //恢复窗口位置函数,窗口状态存放在ini文件中。

  procedure ReadFormPos(Form : TForm);

  var

  RegFile : TIniFile;

  SectName : string;

  begin

  //ini文件中存放Form信息的节名称

  SectName := Form.Name + ' Position';

  //打开与可执行文件名相同的ini文件

  RegFile := TIniFile.Create(

  ChangeFileExt(Application.ExeName,'.ini'));

  //恢复窗口状态

  with Form do begin

  Left := RegFile.ReadInteger(SectName,'Left',Left);

  Top := RegFile.ReadInteger(SectName,'Top',Top);

  Width := RegFile.ReadInteger(SectName,'Width',Width);

  Height := RegFile.ReadInteger(SectName,'Height',Height);

  WindowState := TWindowState(

  RegFile.ReadInteger(SectName,'WindowState',0));

  end;

  //关闭ini文件

  RegFile.Free;

  end;

  //保存窗口位置函数

  procedure SaveFormPos(Form:TForm);

  var

  RegFile : TIniFile;

  SectName : string;

  begin

  SectName := Form.Name + ' Position';

  RegFile := TIniFile.Create(

  ChangeFileExt(Application.ExeName,'.ini'));

  with Form do begin

  RegFile.WriteInteger(SectName,'WindowState',

  integer(WindowState));

  //最大化时,不保存窗口位置

  if WindowState <> wsMaximized then begin

  RegFile.WriteInteger(SectName,'Left',Left);

  RegFile.WriteInteger(SectName,'Top',Top);

  RegFile.WriteInteger(SectName,'Width',Width);

  RegFile.WriteInteger(SectName,'Height',Height);

  end;

  //当要保存状态的窗口是程序主窗口时,要特殊处理。因为主窗口收到最小化消息时,只是把此消息转至Application处理,本身并不最小化。所以我们要判断Application的状态。

  if Form = Application.MainForm then begin

  if IsIconic(Application.Handle) then begin

  Reg File.Write Integer(Sect Name,'WindowState',

  Integer(wsMinimized));

  end;

  end;

  end;

  RegFile.Free;

  end;

  //注册控件

  procedure Register;

  begin

  RegisterComponents('XDCtls', [TPosition]);

  end;

  //TPositon类的实现

  //当主窗口Destroy时,调用此函数,此函数又调用保存的OnDestoy事件处理函数

  procedure TPosition.FormDestroy(Sender: TObject);

  begin

  SaveFormPos(Owner as TForm);

  if Assigned(FOnDestroy) then FOnDestroy(Sender);

  end;

  //控件加载时,恢复父窗口位置,并对父窗口的OnDestroy事件进行替换

  procedure TPosition.Loaded;

  begin

  inherited Loaded;

  //非设计状态才进行处理

  if not (csDesigning in Componentstate) then begin

  ReadFormPos(Owner as TForm);

  FOnDestroy := (Owner as TForm).OnDestroy;

  (Owner as TForm).OnDestroy := FormDestroy;

  end;

  end;

  end.

  完成此单元后,新建一个Package,将此单元包含在其中,编译、安装即可。资源文件Position.dcr,可自行创建合适的图标。使用时,只要将这个控件放到相应的Form即可。下面是我测试时的窗体代码,不用加任何语句就可以自动保存窗体状态。

  unit Unit1;

  interface

  uses

  Windows, Messages, SysUtils, Classes, Graphics,

  Controls, Forms, Dialogs,Position;

  type

  TForm1 = class(TForm)

  Position1: TPosition;

  private

  public

  end;

  var

  Form1: TForm1;

  implementation

  {$R *.DFM}

  end.

  此程序在PWIN97+Delphi5.0下通过

---------------------------------------

unit WinRstor;

INTERFACE

USES SysUtils, Forms;

TYPE {=============================================================}

{------------------------------------------------------------------

Windows restorer object class and related types.

-------------------------------------------------------------------}

EWinRestorer = class( Exception);

TWhatSave = (default, size, location, state);

STWhatSave = set of TWhatSave;

TWinRestorer = class(TObject)

protected

 mIniFile: string;

 mIniSect: string[80];

 mIsInitialized: boolean;

 mDefaultWhat: STWhatSave;

public

 constructor Create( TheApp: TApplication;

   LocalDir: boolean; DefaultWhatSave: STWhatSave);

   {If localDir is true, ini dir is the app dir.  Else, ini dir is the windows dir.}

 procedure SaveWin(TheForm: TForm; What: STWhatSave);

 procedure SaveChildren(TheMDIForm: TForm; What: STWhatSave);

 procedure RestoreWin( TheForm: TForm; What: STWhatSave);

 procedure RestoreChildren(TheMDIForm: TForm; What: STWhatSave);

 property IniFileName: string  read mIniFile;

end;

CONST

 WHATSAVE_ALL = [size, location, state];

VAR

GlobalWinRestorer: TWinRestorer;

IMPLEMENTATION

Uses IniFiles;

constructor TWinRestorer.create;

var fname, path: string[100];

begin

 inherited create;

{Calculate ini file name}

 if default in DefaultWhatSave then

   raise EWinRestorer.create(

    'Attempt to initialize default window position paramaters with set ' +

    ' containing [default] item.  ' +

    'Default params may contain only members of [size, location, state].  ')

 else mDefaultWhat := DefaultWhatSave;

 fname := ChangeFileExt( ExtractFileName( TheApp.exeName), '.INI');

 if LocalDir then begin {parse out path and add to file name}

   path := ExtractFilePath(TheApp.exeName);

   if path[length(path)] <> '\' then

     path := path + '\';

   fname := path + fname;

 end;

{fill object fields}

 mIniFile := fname;

 mIniSect := 'WindowsRestorer';

{It'd be nice to write some notes to a section called [WinRestorer Notes]}

end;

procedure TWinRestorer.RestoreWin;

var FormNm, SectionNm: string[80];   ini: TIniFile;

 n,l,t,w,h: integer; {Left, Top Width, Height}

begin

 ini := TIniFile.create( mIniFile);

 TRY

   SectionNm := mIniSect;

   FormNm := TheForm.classname;

   if default in What then What := mDefaultWhat;

{Update Window State if Necessary}

   if state in What then

     n := ini.ReadInteger( SectionNm, FormNm + '_WindowState', 0);

     case  n of

       1:   TheForm.WindowState := wsMinimized;

       2:  TheForm.WindowState := wsNormal;

       3:   TheForm.WindowState := wsMaximized;

     end;

{Update Size and Location if necessary.}

   with TheForm do begin l:=left; t:=top; h:=height; w:=width; end; {Save current vals.}

   if size in What then begin

     w := ini.ReadInteger( SectionNm, FormNm + '_Width', w);

     h := ini.ReadInteger( SectionNm, FormNm + '_Height', h);

   end;

   if location in What then begin

     t := ini.ReadInteger( SectionNm, FormNm + '_Top', t);

     l := ini.ReadInteger( SectionNm, FormNm + '_Left', l);

   end;

   TheForm.SetBounds(l,t,w,h);

 FINALLY

   ini.free;

 END;

end;

procedure TWinRestorer.RestoreChildren;

var i: integer;

begin

 if TheMDIForm.formstyle <> fsMDIForm then

   raise EWinRestorer.create('Attempting to save window sizes of children for a non MDI parent window.')

 else

   for i := 0 to TheMDIForm.MDIChildCount - 1 do

     RestoreWin( TheMDIForm.MDIChildren[i], what);

end;

procedure TWinRestorer.SaveWin;

var FormNm, SectionNm: string[80];   w : STWhatsave; ini: TIniFile;

begin

 ini := TIniFile.create( mIniFile);

 TRY

   SectionNm := mIniSect;

   FormNm := TheForm.ClassName;

   if default in What then w := mDefaultWhat else w := mDefaultWhat;

   if size in w then begin

     ini.WriteInteger( SectionNm, FormNm + '_Width', TheForm.Width);

     ini.WriteInteger( SectionNm, FormNm + '_Height', TheForm.Height);

   end;

   if location in w then begin

     ini.WriteInteger( SectionNm, FormNm + '_Top', TheForm.Top);

     ini.WriteInteger( SectionNm, FormNm + '_Left', TheForm.Left);

   end;

   if state in w then

     case TheForm.WindowState of

       wsMinimized:   ini.WriteInteger( SectionNm, FormNm + '_WindowState', 1);

       wsNormal:     ini.WriteInteger( SectionNm, FormNm + '_WindowState', 2);

       wsMaximized:   ini.WriteInteger( SectionNm, FormNm + '_WindowState', 3);

     end;

 FINALLY

   ini.free;

 END;

end;

procedure TWinRestorer.SaveChildren;

var i: integer;

begin

 if TheMDIForm.formstyle <> fsMDIForm then

   raise EWinRestorer.create('Attempting to restore window sizes of children for a non MDI parent window.')

 else

   for i := 0 to TheMDIForm.MDIChildCount - 1 do

     SaveWin( TheMDIForm.MDIChildren[i], what);

end;

INITIALIZATION

END.

{This code came from Lloyd's help file!}