In a recent project the end-user should be able to do some settings of a specific control. The control, an InstrumentMeter, has a lot of properties, and only some properties, like color, scale etc. had to be customizable by the end-user.
A very common way to let a user edit properties is to use a RTTI property inspector. The user can then edit properties in a Delphi way. I use the Devexpress RTTI inspector, but there are many alternatives outthere. The RTTI inspector object has a property to link the 'to be inspected control' called InspectedControl of type TPersistent.
Because users may only edit some of the properties I could not set the control there, because all the published properties would become editable.
So I decided to make a wrapper class for the control, which published only the necessary properties and 'links' them to the InstrumentMeter control.
(You can inherit a control and publish only those properties that you want to, but this works only inside of Delphi)
I decided to inherit this class from TPersistent, so that I could set it in my RTTI Inspector.
The class looks somewhat like this:
type
TInstrument = class(TPersistent)
private
public
//the InstrumentControl
property InstrumentControl : TInstrumentControl;
published
//All enduser props
property Kleur: TColor read FColor write SetColor(const Value : TColor);
property ...
end;
Properties set by the user (for instance Kleur) must be saved to a database. I could of course extend a table with fields for all the properties, but having several types of instruments this would give a lot of extra fields.
Why not persist the TInstrument object?
Yeah great idea, stream the object into a blobfield of the database. This can be done easily with a TComponent class, but how do you do this with a TPersistent class?
A TComponent class could be streamed with the TStream WriteComponent method like this:
MyStream.WriteComponent(AComponent);
This stream then, could be saved into a Blobfield and later on read with the TStream ReadComponent method.
I realize that I should inherit from TComponent so that I would not have a problem streaming, but hey let's persist on the TPersistent for now.How to save a TPersistent to a stream?
As far as I know now, this is not possible.
The only way to do this, as far as I know, is to use a DummyComponent (TComponent) with a property holding the TPersistent object, and then streaming both in the database. That works fine!
The code looks like this:
type
TDummyObject = class(TComponent)
private
FPersistent: TPersistent;
public
//Property for holding my Persistent object
property Persistent: TPersistent read FPersistent write FPersistent;
end;procedure SavePersistentToStream(APersistent: TPersistent; AStream: TStream);
var
DummyObject: TDummyObject;
begin
DummyObject:= TDummyObject.Create(nil);
try
DummyObject.Persistent := APersistent;
//write the component into the stream
Stream.WriteComponent(DummyObject);
finally
DummyObject.Free;
end;
end;
procedure LoadPersistentFromStream(APersistent: TPersistent; AStream: TStream);
var
DummyObject: TDummyObject;
begin
DummyObject:= TDummyObject.Create(nil);
try
DummyObject.Persistent := APersistent;
AStream.ReadComponent(DummyObject);
finally
DummyObject.Free;
end;
end;
Writing this I decided to inherit from TComponent anyway (why not?) but the question remains, are there other ways to persist a TPersistent?
3 comments:
Check out Hallvard's blog
http://hallvards.blogspot.com/2006/09/extended-class-rtti.html
the property persistent on the component class must have published visibility...check this out!
The whole idea of streaming a relative lightweight tpersistent is NOT streaming all the added fields in TComponents.
Your solution might be a nice system for "just a quickie", but unfortunately it is not usable for large amounts
Post a Comment