Recent

Author Topic: TForm Create problems  (Read 10034 times)

mtanner

  • Sr. Member
  • ****
  • Posts: 287
TForm Create problems
« on: November 04, 2017, 03:59:59 pm »
I have an app with a number of non-autocreate forms. I have a puzzling bug which I cannot seem to make headway on, so I am looking for guesses/pointers/clues on what to look for.

So I have a form defined as TabcForm, and in my app I do

var ABC:TabcForm.
...
ShowMessage('trace 1');
ABC:=TabcForm.Create(Main);  { where Main is the main window of the app)
ShowMessage('trace 2');


procedure TabcForm.FormCreate(Sender);
begin
    ShowMessage('trace 3');
..

For some forms this works fine, but for others I get "trace 1", but not "trace 2" or "trace 3".

I have other forms in the app for which this method works, and another app in which it works all the time. Obvioulsy I have tried to find what differences there are between the forms, but cannot find anything. So any inspired guesses, or suggestions on where to look, gratefullt received.

The code is too large to put on here.

FTurtle

  • Sr. Member
  • ****
  • Posts: 292
Re: TForm Create problems
« Reply #1 on: November 04, 2017, 04:56:08 pm »
Is there something between these two lines: ?

Code: Pascal  [Select][+][-]
  1. ABC:=TabcForm.Create(Main);  { where Main is the main window of the app)
  2. ShowMessage('trace 2');
  3.  

Go to Events tab and ensure that "FormCreate" in "OnCreate".

P.S. I hope wrong comment is only at forum.
« Last Edit: November 04, 2017, 05:04:57 pm by FTurtle »

Thaddy

  • Hero Member
  • *****
  • Posts: 18321
  • Here stood a man who saw the Elbe and jumped it.
Re: TForm Create problems
« Reply #2 on: November 04, 2017, 05:04:35 pm »
Same as I think: Create forms with owner
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

mtanner

  • Sr. Member
  • ****
  • Posts: 287
Re: TForm Create problems
« Reply #3 on: November 04, 2017, 06:09:34 pm »
I should have explained better.
  The FormCreate event is in the "correct" place.
The code fragment above it is somewhere else. Basically think of there being a button on the Main form with associated code that tries to create the form with the code fragment.
I've done everything I can think of to find out what is going wrong - at the moment I'm building a test form, very simple, that gets created as above. This works ok, so I'm thinking of obscure bugs in the code that does the application functions within the created form, and gradually putting code in the test form tp check out the linkages between the forms and various data structures in my app. Experience suggest it will eventually turn out to be something really stupid or obscure on my part, but it's taking much longer than usual to track this think down..

I have to confess I'm still on XP - in process of moving everything to later Windows, but still using XP because I'm converting stiff from Delphi6/TeeChart for which I need XP. So I suppose that does raise the possibility of Lazarus/FPC being incompatible with XP, though it's working fine with a lot of other very similar code. And then why would the Create fail on some forms but not others? For the record I'm using Lazarus #1.6.4, FPC 3.0.2, SVN 54278.

FTurtle

  • Sr. Member
  • ****
  • Posts: 292
Re: TForm Create problems
« Reply #4 on: November 04, 2017, 06:27:39 pm »
1. Lazarus has not any problem with Windows XP.
2. Use debugger. Set breakpoint on line "ABC:=TabcForm.Create(Main);" and go thru code via F7/F8.
 

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: TForm Create problems
« Reply #5 on: November 04, 2017, 06:31:22 pm »
Forms should be created with CreateNew:
Code: Pascal  [Select][+][-]
  1. ABC:=TabcForm.CreateNew(Main);
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

FTurtle

  • Sr. Member
  • ****
  • Posts: 292
Re: TForm Create problems
« Reply #6 on: November 04, 2017, 07:02:41 pm »
Forms should be created with CreateNew:
Code: Pascal  [Select][+][-]
  1. ABC:=TabcForm.CreateNew(Main);

Only in case of form created by clean code without designer.

jamie

  • Hero Member
  • *****
  • Posts: 7306
Re: TForm Create problems
« Reply #7 on: November 04, 2017, 10:56:40 pm »
Are you freeing previous instants of the form before re-using same instant variable?

 I guess you could implement the Close Event and set it to caFree to make sure but still its possible
you can over creating?

 have you tried HeapTrc (heap Trace)? that is in the project options under debug.

 When you exit your app, it should report all memory blocks reclaimed.

 If not, you are not freeing your forms and possibly over creating.
The only true wisdom is knowing you know nothing

mtanner

  • Sr. Member
  • ****
  • Posts: 287
Re: TForm Create problems
« Reply #8 on: November 05, 2017, 09:03:11 am »
Thanks for those comments.

Would appreciate some clarification on CreateNew vs Create. My understanding is that CreateNew is required for forms not designed in the form designer. Presumably CreateNew builds resources for the form. My forms are all designed in the form designer and have a lfm file. I then take them out of auto-create and delete the declaration of the form variable that Lazarus adds.

I don't think it is over-creating. I get the problem of first create of the problem form(s) after starting the application. I will check the heap trace, but my program structure for creating/deleting files has worked for quite a while, so I think it's ok.

I had a look at the lpi file for any clues. The form that gives me trouble is in unit number 199. Made we wonder if there is any significance or practical limit to the number of units in a Lazarus app.

FTurtle

  • Sr. Member
  • ****
  • Posts: 292
Re: TForm Create problems
« Reply #9 on: November 05, 2017, 12:28:21 pm »
Would appreciate some clarification on CreateNew vs Create. My understanding is that CreateNew is required for forms not designed in the form designer.

Yes, right.

Quote
Presumably CreateNew builds resources for the form.


Not exactly in that way.
In pas file for form made in designer you can see line:

Code: Pascal  [Select][+][-]
  1. {$R *.lfm}

This line puts you lfm file to resources.
When you call Create, constructor try to find in resources this file and create appropriate components. If this file not in resoures you will get error.
CreateNew not trying to find any resources and just create empty form and all components will created only by your code.

Quote
My forms are all designed in the form designer and have a lfm file. I then take them out of auto-create and delete the declaration of the form variable that Lazarus adds.

It is a good approach.

Quote
I had a look at the lpi file for any clues. The form that gives me trouble is in unit number 199. Made we wonder if there is any significance or practical limit to the number of units in a Lazarus app.

I didn't hear about such limits.

mtanner

  • Sr. Member
  • ****
  • Posts: 287
Re: TForm Create problems
« Reply #10 on: November 06, 2017, 10:20:55 pm »
I am still struggkibg with this problem,

If I use CreateNew instead of create then the form does get created and I can display it. Of course all the controls are missing from it, so it's not a solution, just a clue.

Does this mean the somehow the lfm file is screwed up? How can I check an lfm vile for validity?

I am also getting a little confused over form names. I thought that each window in an application had to have a unique name, so I have been assigning unique names when I create the forms. But I see there are posts saying do not change the form name except in the Designer. I need to create multiple instances of the same form. I'd appreciate clarification.

I did remove the assignment of unique names, just leaving the Designer-assigned name. Windows did not complain but the main problem persists.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: TForm Create problems
« Reply #11 on: November 06, 2017, 11:09:42 pm »
You basically have two choices:
  • Create forms which have .lfm resources with Application.CreateForm()
  • Create resourceless forms with CreateNew()
Option 1 is the normal RAD route.
Lazarus creates all your forms for you (via Application.CreateForm() calls which it adds in the .lpr), and the Designer creates .lfm resources for all such automatically created forms (i.e. both for the default Form1, and for any further forms you generate via File->New Form).
You can tweak this option via the Project Options's Forms page which lets you specify which forms will be auto-created. If you have a lot of forms, you might not want or need all of them created at start-up, and so you can create some of them by manual calls to Application.Createform() only at the time you need them.
Lazarus generates and manages each .lfm file corresponding to its form unit file as you drop controls on forms and move them/delete them etc. This management all happens automatically in the background, and the .lfm is always kept in sync with the form unit file (unless you edit the .lfm outside the IDE and break the synchronisation).

Option 2 lets you create any form (with the possible exception of the main form) entirely in code, with no .lfm resource at all associated with such dynamically created forms. This is a far more verbose option, since you have to duplicate creation of all the controls you want on your form, and setting all their properties, parentage and positioning entirely in code (you are basically duplicating manually what Lazarus does for you automatically  when it reads a form .lfm file as the template for the form's subcomponent creation and placement).

Although in theory you have a further option to create forms via calls to e.g. TForm2.Create(), it is not a route I would recommend since you do not seem to understand fully the complexities of form creation and form resource management.
Using Application.CreateForm() together with form resource management via .lfms is a much safer option for you, since then all your forms are managed by the Application, and you will not have to worry about when or how to free your forms. The Application instance will take care of it for you. And the IDE will ensure your .lfm files are always valid.
« Last Edit: November 06, 2017, 11:25:36 pm by howardpc »

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1265
Re: TForm Create problems
« Reply #12 on: November 07, 2017, 12:22:24 am »
ShowMessage('trace 1');
...
ABC:=TabcForm.Create(Main);  { where Main is the main window of the app)
ShowMessage('trace 2');

procedure TabcForm.FormCreate(Sender);
begin
    ShowMessage('trace 3');
..

Only reason I can think that you never saw "Trace 2" is that an exception was raised.  Do you have debug info on?  Maybe you're suppressing the exception, but not handling the consequences correctly (Try Except).  With Debug Off, you're not even seeing the exception in the debugger.  I know, I know.  Seems highly unlikely.  The truth is I'm clutching at straws, no real idea why you're not seeing "trace 2".

One reason I can think that you are not seeing "Trace 3" is that the FormCreate event hook has dropped off.  Check in the Object Inspector, ensure that the FormCreate event is still hooked to the FormCreate procedure

Are you using Form Inheritance?  I've had a few irritatingly erratic issues with the FormCreate and FormDestroy events dropping off when I use Form Inheritance.  In my case I'm bending a few rules, using a form in a shared Package as the base of my descended forms which are in the project.  Given the IDE does not support this (File - New... does not list forms in Packages), I've not raised this as an issue.

The workaround I've adopted is to use good old fashioned Constructors and Destructors instead of events.  They're still there for TForm, but are not public.  Up in Protected from memory.

So, if you're using Form Inheritance and bending the same rules I am, try switching to using Constructor Create/Destructor Destroy instead of the FormCreate/FormDestroy events....

Oh, I also see FormCreate and FormDestroy drop out when I use TFrames, and again I've reverted to using Constructor/Destructors there.  Again, I'm using Form Inheritance with my frames, and my base frame is in that same shared package...

But I'm at a loss why you're not seeing 'trace 2'
« Last Edit: November 07, 2017, 12:25:55 am by Mike.Cornflake »
Lazarus Trunk/FPC Trunk on Windows [7, 10]
  Have you tried searching this forum or the wiki?:   http://wiki.lazarus.freepascal.org/Alternative_Main_Page
  BOOKS! (Free and otherwise): http://wiki.lazarus.freepascal.org/Pascal_and_Lazarus_Books_and_Magazines

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TForm Create problems
« Reply #13 on: November 07, 2017, 02:13:01 am »
Guessing!

Are you creating these forms inside some event of another form where this event will be called during its creation, like OnCreate or OnAfterConstruction... etc. for instance?

TForm.Create lands in:
Code: Pascal  [Select][+][-]
  1. constructor TCustomForm.Create(AOwner: TComponent);
  2. begin
  3.   GlobalNameSpace.BeginWrite;
  4.   try
  5.     CreateNew(AOwner, 1); // this calls BeginFormUpdate, which is ended in AfterConstruction
  6. ...
  7.   finally
  8.     GlobalNameSpace.EndWrite;
  9.   end;
  10. end;
  11.  

GlobalNameSpace.BeginWrite will wait until the previous object call GlobalNameSpace.EndWrite which will not happen.

This explains why using CreateNew did work and did not seem to have this problem. CreateNew does not call GlobalNameSpace.BeginWrite.
« Last Edit: November 07, 2017, 02:15:03 am by engkin »

FTurtle

  • Sr. Member
  • ****
  • Posts: 292
Re: TForm Create problems
« Reply #14 on: November 07, 2017, 05:37:10 am »
How can I check an lfm vile for validity?

Main menu/Tools/Check LFM File in Editor.

I am also getting a little confused over form names. I thought that each window in an application had to have a unique name, so I have been assigning unique names when I create the forms. But I see there are posts saying do not change the form name except in the Designer. I need to create multiple instances of the same form. I'd appreciate clarification.

You should not touch Name at runtime. LCL will do it on its own. When you will create new instanses of TabcForm, names automatically will be changed to:
abcForm, abcForm_1, abcForm_2, ...

I did remove the assignment of unique names, just leaving the Designer-assigned name. Windows did not complain but the main problem persists.

It is good time to stop generate theories and do one of two (or both) things:

1. Show more code.

2. Use debugger and go thru code step-by-step.
How to do it:

1. Set breakpoints in interesting places. For this click on gutter. You will get red line. Set first breakpoint on "ShowMessage('trace 1');"
2. Run program and press necessary buttons.
3. Program will paused on breakpoint. Next executing line will pointed by green arrow.
4. Go thru code with or without entering to procedures via F7/F8.

 

TinyPortal © 2005-2018