Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2013-02

How to load the Form from LFM-file at run time?

6 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Александр С.

Example: there is a empty form that has an event: another form (from LFM-file) to be loaded instead of this form by double-clicking on old form at run time.

I tried several ways to do this, for example:
1. File -> FileStream -> BinStream -> BinStream.ReadComponent(Form)
2. ReadComponentResFile()

These methods have drawbacks:
a. Double-clicking event from the old form doesn't disappear in new b. Need to register (RegisterClasses) for all the classes that are in the new form. Parsing the LFM-file, you can get the names of classes in the strings. What content should have a function "function StringToClass(AStr: string): TClass", to be able to call "RegisterClass(StringToClass(AStr))" ?

3. File -> StringStream -> Reader -> Reader.ReadComponent -> InsertComponent But my methods does not work. Could you please help me: how to load Form from LFM-file at run time?

Reply by email

Hans-Peter Diettrich
to Александр С.
Show quoted text 7 lines
Example: there is a empty form that has an event: another form (from LFM-file) to be loaded instead of this form by double-clicking on old form at run time. I tried several ways to do this, for example: 1. File -> FileStream -> BinStream -> BinStream.ReadComponent(Form) 2. ReadComponentResFile()

I'm using (2) in an old Delphi program.

These methods have drawbacks: a. Double-clicking event from the old form doesn't disappear in new

I create a new (empty) form.

Show quoted text 5 lines
b. Need to register (RegisterClasses) for all the classes that are in the new form. Parsing the LFM-file, you can get the names of classes in the strings. What content should have a function "function StringToClass(AStr: string): TClass", to be able to call "RegisterClass(StringToClass(AStr))" ?

You have to know the units where the class declarations reside, and Use them in the registering unit. Then register all classes by name.

When you design the forms, you have all you
can exclude the .pas files, when you only want to load the lfm files.

DoDi

Reply by email

Mattias Gaertner
to Александр С.: Example: there is a empty form that has an event: another form (from LFM-file) to be…
Show quoted text 7 lines
Example: there is a empty form that has an event: another form (from LFM-file) to be loaded instead of this form by double-clicking on old form at run time. I tried several ways to do this, for example: 1. File -> FileStream -> BinStream -> BinStream.ReadComponent(Form) 2. ReadComponentResFile()

Have you seen the example in lazarus/examples/componentsstreaming/ ?

These methods have drawbacks: a. Double-clicking event from the old form doesn't disappear in new

When you load a lfm you have to start with a newly created form. There is no method to "reset" a form to its initial state.

Show quoted text 5 lines
b. Need to register (RegisterClasses) for all the classes that are in the new form. Parsing the LFM-file, you can get the names of classes in the strings. What content should have a function "function StringToClass(AStr: string): TClass", to be able to call "RegisterClass(StringToClass(AStr))" ?

See the example.

3. File -> StringStream -> Reader -> Reader.ReadComponent -> InsertComponent But my methods does not work. Could you please help me: how to load Form from LFM-file at run time?

Mattias

Reply by email

Александр С.
You have to know the units where the class declarations reside

Here is an example LFM-file:

object Form1: TForm1
Left = 224
Height = 240
Top = 146
Width = 320
Caption = 'Form1'
ClientHeight = 240
ClientWidth = 320
LCLVersion = '1.0.6.0'
object Memo1: TMemo
Left = 36
Height = 121
Top = 78
Width = 146
Lines.Strings = (
'Memo1'
)
TabOrder = 0

  end
  object ProgressBar1: TProgressBar
    Left = 46
    Height = 24
    Top = 24
    Width = 240
    TabOrder = 1
  end
  object SpinEdit1: TSpinEdit
    Left = 207
    Height = 21
    Top = 160
    Width = 84
    TabOrder = 2
  end
  object SelectDirectoryDialog1: TSelectDirectoryDialog
    left = 210
    top = 91
  end

end

How can I get the units where the class declarations reside, knowing only this information? When I loading the LFM-file, I know LFM content only.

Have you seen the example in lazarus/examples/componentsstreaming/ ?

Yes, I have. This example is incorrect in my case, because:
1) No need to register classes -- everything is already registered
2) The process of copying the component is performed in the example. In my case it happens with Forms; and it is not copied -- replacement.

See the example

Unfortunately, he could not help me in this case, it is too simple.

Reply by email

Mattias Gaertner
to Александр С.
Show quoted text 46 lines
>You have to know the units where the class declarations reside Here is an example LFM-file: object Form1: TForm1 Left = 224 Height = 240 Top = 146 Width = 320 Caption = 'Form1' ClientHeight = 240 ClientWidth = 320 LCLVersion = '1.0.6.0' object Memo1: TMemo Left = 36 Height = 121 Top = 78 Width = 146 Lines.Strings = ( 'Memo1' ) TabOrder = 0 end object ProgressBar1: TProgressBar Left = 46 Height = 24 Top = 24 Width = 240 TabOrder = 1 end object SpinEdit1: TSpinEdit Left = 207 Height = 21 Top = 160 Width = 84 TabOrder = 2 end object SelectDirectoryDialog1: TSelectDirectoryDialog left = 210 top = 91 end end How can I get the units where the class declarations reside, knowing only this information? When I loading the LFM-file, I know LFM content only.

Dodi probably meant the "Register" procedures. They register the LCL classes via RegisterComponents. But some do more than this. They are used by the IDE.
You don't need the units, you need to register all needed classes or provide a OnFindClass hook, as shown in the example.

Show quoted text 6 lines
> Have you seen the example in lazarus/examples/componentsstreaming/ ? Yes, I have. This example is incorrect in my case, because: 1) No need to register classes -- everything is already registered 2) The process of copying the component is performed in the example. In my case it happens with Forms; and it is not copied -- replacement.

You can not replace with lfm. lfm only adds components or sets properties.
ReadComponentFromBinaryStream can read forms too.
Alternatively you can use TReader.ReadRootComponent.

> See the example Unfortunately, he could not help me in this case, it is too simple.

Here is a complex example:
lazarus/designer/jitforms.pp
Search for AddJITComponentFromStream.

Mattias

Reply by email

Александр С.
You don't need the units, you need to register all needed classes

lfm only adds components or sets properties. So I can get only a class names as strings. TClass is required for RegisterComponents. I do not know how to convert a string to TClass.

you need to ? provide a OnFindClass hook, as shown in the example.

It works for the component, but will it work for TForm? I tried this, I made a few changes in the example, I did not succeed:

Index: mainunit.pas
===================================================================
--- mainunit.pas	(revision 40336)
+++ mainunit.pas	(working copy)
@@ -53,7 +53,7 @@
 begin
   AStream:=TMemoryStream.Create;
   try
-    WriteComponentAsBinaryToStream(AStream,AGroupBox);
+    WriteComponentAsBinaryToStream(AStream,CompStreamDemoForm);
     SaveStreamAsString(AStream);
   finally
     AStream.Free;
@@ -72,9 +72,7 @@
     ReadStreamFromString(AStream);
     NewComponent:=nil;
     ReadComponentFromBinaryStream(AStream,NewComponent,
-                                  @OnFindClass,DestinationGroupBox);
-    if NewComponent is TControl then
-      TControl(NewComponent).Parent:=DestinationGroupBox;
+                                  @OnFindClass);
   finally
     AStream.Free;
   end;
@@ -158,8 +156,8 @@
   DestinationGroupBox.
 }
 begin
-  while DestinationGroupBox.ComponentCount>0 do
-    DestinationGroupBox.Components[0].Free;
+  while CompStreamDemoForm.ComponentCount>0 do
+    CompStreamDemoForm.Components[0].Free;
 end;
 procedure TCompStreamDemoForm.OnFindClass(Reader: TReader;
@@ -167,8 +165,8 @@
 begin
   if CompareText(AClassName,'TGroupBox')=0 then
     ComponentClass:=TGroupBox
-  else if CompareText(AClassName,'TCheckBox')=0 then
-    ComponentClass:=TCheckBox;
+  else if CompareText(AClassName,'TCompStreamDemoForm')=0 then
+    ComponentClass:=TCompStreamDemoForm;
 end;
 end.

Reply by email