在Delphi中,只有published段的属性在设计时可控.
Public域的属性只能在运行期使用,比如一个简单类型可以手工持久化,但是没有任何实际意义的,除了加大DFM文件以外.
实际上持久化不仅仅中所谓设计期使用,运行时也可以执久化,你可以把某个控件的某一时该的状态永久的保存下来,而且在之后的个时该再装载进来.
unit MyEdit;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, StdCtrls, Dialogs;
type
TMyEdit = class(TEdit)
private
FMyComp: TEdit;
procedure LoadCompProperty(Reader: TReader);
procedure StoreCompProperty(Writer: TWriter);
protected
procedure DefineProperties(Filer: TFiler); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
// published
//不发布此属性,采用手工持久化
//安装此控件后,从组件面板上拖到窗体上,按Atl+F12就报"Stream read errror"
property MyComp: TEdit read FMyComp write FMyComp;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Standard', [TMyEdit]);
end;
{ TMyEdit }
constructor TMyEdit.Create(AOwner: TComponent);
begin
inherited;
Width:=150;
Height:=150;
end;
procedure TMyEdit.LoadCompProperty(Reader: TReader);
begin
Reader.ReadListBegin;
if Reader.ReadBoolean then
FMyComp := TEdit(Reader.ReadComponent(FMyComp));
Reader.ReadListEnd;
end;
procedure TMyEdit.StoreCompProperty(Writer: TWriter);
begin
Writer.WriteListBegin;
Writer.WriteBoolean(FMyComp <> nil);
if FMyComp <> nil then
Writer.WriteComponent(FMyComp);
Writer.WriteListEnd;
end;
procedure TMyEdit.DefineProperties(Filer: TFiler);
function DoWrite: Boolean;
begin
if Filer.Ancestor <> nil then { check Ancestor for an inherited value }
begin
if TMyEdit(Filer.Ancestor).FMyComp = nil then
Result := FMyComp <> nil
else if (FMyComp = nil) or
(TMyEdit(Filer.Ancestor).FMyComp.Name <> FMyComp.Name) then
Result := True
else Result := False;
end
else { no inherited value -- check for default (nil) value }
Result := FMyComp <> nil;
end;
begin
inherited; { allow base classes to define properties }
Filer.DefineProperty('MyComp', LoadCompProperty, StoreCompProperty, DoWrite);
end;
destructor TMyEdit.Destroy;
begin
inherited;
end;
initialization
RegisterClass(TMyEdit);
RegisterClass(TComponent);
end.
以下是运行时使用的代码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, MyEdit, UnitComponent;
type
TForm1 = class(TForm)
ButtonSave: TButton;
ButtonLoad: TButton;
SaveDialog1: TSaveDialog;
OpenDialog1: TOpenDialog;
ListBox1: TListBox;
ButtonInit: TButton;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ButtonSaveClick(Sender: TObject);
procedure ButtonLoadClick(Sender: TObject);
procedure ButtonInitClick(Sender: TObject);
private
{ Private declarations }
public
FMyEdit:TMyEdit;
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FMyEdit:=TMyEdit.Create(Self);
FMyEdit.Parent:=Self;
FMyEdit.Top:=200;
FMyEdit.MyComp:=Edit1;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FMyEdit.Free;
end;
procedure TForm1.ButtonSaveClick(Sender: TObject);
var
lSaveStream: TMemoryStream;
begin
if SaveDialog1.Execute then
begin
lSaveStream := TMemoryStream.Create;
try
lSaveStream.WriteComponent(FMyEdit);
lSaveStream.Seek(0, 0);
lSaveStream.SaveToFile(SaveDialog1.FileName);
finally
lSaveStream.Free;
end;
end;
end;
procedure TForm1.ButtonLoadClick(Sender: TObject);
var
lLoadStream : TMemoryStream;
i: integer;
begin
lLoadStream := TMemoryStream.Create;
try
if OpenDialog1.Execute then
begin
lLoadStream.LoadFromFile(OpenDialog1.FileName);
lLoadStream.Seek(0, 0);
try
lLoadStream.ReadComponent(FMyEdit);
Except
end;
FMyEdit.Text:='aadfdfdfdfd';
FMyEdit.MyComp.Text:='aadfdfdfdfd';
end;
finally
lloadStream.Free;
end;
end;
procedure TForm1.ButtonInitClick(Sender: TObject);
begin
FMyEdit.Text:='aaa';
FMyEdit.MyComp.Text:='aaaaaa';
end;
end.
请注意在这个例子中,FMyComp并没有在TMyEdit.Create中创建,而是在使用的时候再赋值,所以MyComp是一个可读写属性.
这样做的原因是:
procedure TMyEdit.LoadCompProperty(Reader: TReader);
begin
Reader.ReadListBegin;
if Reader.ReadBoolean then
FMyComp := TEdit(Reader.ReadComponent(FMyComp));
Reader.ReadListEnd;
end;
这个过程中,Reader.ReadComponent(FMyComp)过程已经创建了一个TEdit类型的对象,并且它的名称与FMyComp相同,同时把它赋给了FMyComp,在TMyEdit.Create中创建,将会造成资源泻漏.
该代码可以把运行时的FMyEdit对象的所有状态都保存起来,并且把它的属性对应的Edit1的状态作为它的子对象一起保存起来.