[Lazarus] Saving user created component structure to LFM file
"Leonardo M. Ramé"
l.rame at griensu.com
Mon Jan 12 15:11:39 CET 2009
In Delphi you have to explicitly set the subcomponent:
Example:
constructor TMyComponent.create....
begin
...
FSubComponent := TSubComponent.Create(Self);
...
FSubComponent.SetSubComponent(True);
...
end;
Leonardo M. Ramé
Griensu S.A. - Medical IT Córdoba
Tel.: 0351 - 4247979
Martin Friebe escribió:
> Mattias Gaertner wrote:
>
>>> [...]
>>> Thanks, I think I found a better way.
>>>
>>> The outer container has no nested components of it's own. It seems I
>>> can hook into (override) TComponent.WriteState which is calling
>>> WriteComponentData (properties, then Children). Since no children are
>>> there, I can make my own calls to WriteComponent from there,
>>> supplying all the components, of all the helper objects.
>>>
>>> On Read, I can Hook into ReadState. I can let the reader add them
>>> normally, and sort them out/once they have been read by the reader.
>>>
>>> The remaining question is: Does that look like something that will
>>> stay compatible with future code? The generated LFM file definitely
>>> looks like any LFM file (it has a component, with properties first
>>> then other nested Components)
>>>
>>>
>> To store a property that is a component and which is not owned by the
>> Lookuproot (form, datamodule, frame) you must set the csSubComponent
>> flag in ComponentStyle.
>>
>>
> yes, I found the csSubComponent. But it stores the only the properties
> of the SubComponent, not the Component's Class.
>
> SubComponent does (Within the list of properties of the actual component):
> MySubCompProp.Value1 = 120
> MySubCompProp.Foo = 'abc'
>
> And also subcomps, look (correctly) at the definition of the property.
> It the Property is defined as TFoo (" property mySubCompProp: TFoo reads
> FMyFoo write FMyFoo;" , then all properties known by this class (TFoo)
> are stored. In My case the actual Object may be a descend and of TFoo
> (that is the objects stored in FMyFoo), and have additional Properties
> (This additional Properties would be lost)
>
>
> My Components are in a TList, the have different classes, so I need to
> save them the same way like nested components:
> object MySubCompFromListClassABC: TSubCompClassABC
> Value1 = 120
> end;
>
>
> The Real Background is SynEdits Gutter.
>
> The Gutter, I have managed to get saved. (via csSubComponent).
> But then the Gutter has a list of GutterParts (all of them Objects (and
> I can/will make them Components)). I need to save all those GutterParts.
> [ I know, I will also need a Property Editor for the object inspector,
> but that's not the issue ]
>
> If A Gutter is created, with a new SynEdit, and *not* loaded from LFM;
> then it creates a default set.
> If it is loaded, it needs to remove the default set (can be done in
> ReadState of SynEdit (SynEdit can inform the gutter) / Can depend on The
> LCL Version, so loading a 0.9.26 form, will keep the defaults, as no
> saved parts can exist)
>
>
>> To store a list use TCollection. If you can not use TCollection please
>> explain why not.
>>
>>
> Because All collection Items a of the same class. If I make that
> TGutterPartBase, then only properties exposed by TGutterPartBase are
> saved. but each GutterPart has additional published properties. (Same
> applies, if I make the CollectionItem a wrapper class with a property
> "property TheRealGutterPart: TGutterPartBase" => because as
> csSubComponen it does not save the class-info)
> Also even If I manage to get this subclasses into the collection (which
> is hard enough, as it is not supposed to be), If the collection is
> loaded, it restores them all to the base class, because it never saved
> the class-info
>
>> To store data of arbitrary length/format, use DefineProperties. This
>> has a drawback: In case of an error the IDE can not help fixing it.
>>
>>
> DefineProperties only takes simple values. Because in define properties
> I must give it the name. Then In Read/WriteProc I deal with the value.
> So define Property will always create an LFM entry like:
> MyDefinedPropertyName = xxx
> xxx Comes from the writecallback.
>
> If the write callback attempts to do WriteComponent, then this will fail
> later, when the binary format is translated into text-lfm-format
> (because " MyDefinedPropertyName = MyObject: TMyClass" is not allowed
>
> That is even, if the WriteCallback starts a list first, it will still fail.
> MyDefinedPropertyName = (
> MyObject: TMyClass
> ....
>
> With "DefineProperties" I have 2 (undesirable) possibilities:
> 1) use DefineBinarryProperties => and write my own format, no one can
> edit it, and why invent the wheel again?
> 2) use DefineProperties and define a large set of properties:
> - define a classname property for each of my objects
> - and define a property for each value that each of my objects needs
> to store.
> Again there is code (WriteComponent) that does streaming of objects
> including class info; why invent the wheel again?
>
> ---------------
>
> So as I see it I found 2 possibilities
>
> 1) The GutterParts are created as components owned by the SynEdit (or
> does it have to be the form; if it does have to be the form then there
> will be issues if there is more than one synedit.... ). that will be a
> lot of easy to break maintenance work. because you need to search
> through the component list to find the Objects.
> And when loading I still need to remove the Objects created in
> Synedit.Create or I get double entries.
> - Also I tried it, and SynEdit did not seem to stream them (MyGutterPart
> := TcomponentBasedClass.Create(TheSynEditAsOwner);) => nothing in the lfm
>
> 2) Maintain the objects as they are, but use SynEdit.WriteState to
> append them to the lfm
> (They can easily be caught, if they get read (by the default reader)
> during loading
>
>
> Best Regards
> Martin
> _______________________________________________
> Lazarus mailing list
> Lazarus at lazarus.freepascal.org
> http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
>
>
More information about the Lazarus
mailing list