Recent

Author Topic: Is there an event triggered when an object is being read from the *.lfm file?  (Read 1474 times)

bhreis88

  • New Member
  • *
  • Posts: 27
Hi all,

is there an event which is triggered only when the properties of an object are being read from the *.lfm file?

I am modifying a custom component and would like to add a property called "CompVersion", to be able to make version specific changes. The idea is that if the custom component is already stored in the *.lfm as an older version, the "CompVersion" property will be retrieved as null, then the changes should not apply. At the same time, the "CompVersion" property should only be written if the component is new, like manually dropped on the form or dynamically created.

I made some attempts of implementing this via the ComponentState property without success. csDesigning gets active for the custom component even if other components are edited. So I don't know when to properly write "CompVersion" without also updating the property for previous versions of the component.

Thanks for your time

Thaddy

  • Hero Member
  • *****
  • Posts: 14159
  • Probably until I exterminate Putin.
Better way is to simply use a version control system.
Specialize a type, not a var.

bhreis88

  • New Member
  • *
  • Posts: 27
Thanks, Thaddy. I will keep that in mind.

But I would still like to know the answer to this:
Quote
is there an event which is triggered only when the properties of an object are being read from the *.lfm file?

Thaddy

  • Hero Member
  • *****
  • Posts: 14159
  • Probably until I exterminate Putin.
No.
Specialize a type, not a var.

HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
all component call the method loading before they start loading from a stream and when they have finished loading the call the method loaded. On your custom controls you can override those two methods to raise any events you like (or not). Also while the properties are set from the stream the componentstate set has the csLoading flag set. ee
Code: Pascal  [Select][+][-]
  1. if csloading in ComponentState then
  2. begin
  3.   Dance robot dance.
  4. end;
  5.  
that should be good enough for your goals although I admit I only read the first line of your message.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
As HeavyUser said, to act whe the control has been loaded you have to override the method Loaded, as in:

Code: Pascal  [Select][+][-]
  1. TForm1 = class(TForm)
  2.   {... other fields/methods ...}
  3. protected
  4.   procedure Loaded; override;
  5. end;
  6.  
  7. {... etc...}
  8.  
  9. procedure TForm1.Loaded;
  10. begin
  11.   inherited Loaded;
  12.    {Do whatever else you want}
  13. end;

If you want to act while the component is being loaded, do the same but with the Loading method.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9754
  • Debugger - SynEdit - and more
    • wiki
You got Loaded, when all is done.

You can use https://www.freepascal.org/docs-html/rtl/classes/tfiler.defineproperty.html to declare your custom property, and get called if it is read.

You need to  tell the IDE to ignore this property RegisterPropertyToSkip together with the registration of your component.

bhreis88

  • New Member
  • *
  • Posts: 27
Thanks HeavyUser, lucamar and Martin_fr!

All your answers have contributed to my understanding of the mechanics behind loading properties from a stream/*.lfm and a solution is successfully implemented!  :D

What worked specifically in my case was this:
- new private property LoadedFromLFM as boolean
- new public property CompVersion as integer
- override Create to set "if (csDesigning in self.ComponenState) then self.LoadedFromLFM:=False;"
- override DefineProperties(Filer: TFiler)
- new procedure LoadVersionProperty(Reader: TReader)
- new procedure StoreVersionProperty(Writer: TWriter)
- override Loaded to set "LoadedFromLFM:=True;" and implement version specific methods using CompVersion
- also:
Code: Pascal  [Select][+][-]
  1. procedure TCustomComp.DefineProperties(Filer: TFiler);
  2. begin
  3.   inherited DefineProperties(Filer);
  4.   Filer.DefineProperty('CompVersion', LoadVersionProperty, StoreVersionProperty, True);
  5. end;    
  6.  
  7. procedure TCustomComp.LoadVersionProperty(Reader: TReader);
  8. begin
  9.   CompVersion := Reader.ReadInteger;
  10. end;
  11.  
  12. procedure TCustomComp.StoreVersionProperty(Writer: TWriter);
  13. begin
  14.   if not self.LoadedFromLFM then
  15.     CompVersion := UpdatedValue;
  16.   Writer.WriteInteger(CompVersion);
  17. end;
  18.  

The final part with the check for LoadedFromLFM is necessary because CompVersion didn't exist in previous versions. So I had to make sure CompVersion would only be updated if the component is manually dropped on the form. Otherwise, old components loaded from *.lfm would also be updated and I would miss this information.

As mentioned in the answers, the order of the methods is the following:
- Dropping component on form: Create --> DefineProperties
- Opening a saved project: Create --> DefineProperties (sometimes?) --> Loaded
- Compiling and running: DefineProperties --> Create --> Loaded
« Last Edit: January 30, 2020, 04:43:45 pm by bhreis88 »

 

TinyPortal © 2005-2018