一些比较专业的软件都有自动保存窗口运行状态的功能,具体的方法都是在窗口关闭前将其状态保存到注册表中或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!}