Differences in Form Initialization between Delphi and Lazarus?
Asked Answered
W

1

6

MainForm creates some secondary Frame objects at runtime to display various option panels.

Here's a typical constructor for one of those frame classes (they each extend TFrame):

constructor Tframe2.Create(AOwner: TComponent);
begin
    inherited;
    edTime.Text := '12:00pm'; //edTime is a TEdit control. this line is where it throws the exception
    //etc.
end;

This code worked fine in Delphi (whether or not it was the right way to do things), but the same code in Lazarus keeps throwing an EInvalidOperation exception, because the control (TEdit) has no parent "window" assigned yet (rsControlHasNoParentWindow), which actually kind of makes sense when I examine the code because the parent doesn't appear to be getting assigned until after the constructor is called.

Here is the code in MainForm the initializes the secondary frame:

if Assigned(frame) then FreeAndNil(frame);
case Node.AbsoluteIndex of
    optInterval: frame := Tframe2.Create(Self); //here's where the constructor gets called.
    //etc
end;
frame := TframeOther.Create(Self); 
if Assigned(frame) then
begin
    frame.Parent := panOptions; //here's where Tframe2's parent gets set
    frame.Align := alClient;
end;  

So can anyone explain whether there's any important differences between Delphi and Lazarus as far as form initialization sequence?

And what the most standard way to resolve this type of initialization order problem would be? Comparing to other languages I'm more familiar with, there might be different strategies to resolve such errors. I could add another parameter to the constructor, or if there's a method that gets called post constructor pre-drawing it on the screen that I could override I could relocate that code, or just make a helper method and call it after setParent gets called. Any particular best practice here?

Edit]: It appears this may be specific to TEdit in some way. It looks like the lines initializing the state for checkboxes are not having the same issue. Could this just be a bug in Lazarus?

Wilbertwilborn answered 26/9, 2012 at 4:19 Comment(4)
I don't know if that fix the problem, but set inherited Create(AOwner); in the create procedure.Shirker
Try simple code TEdit.Create(nil).Text := '12345'; This code creates parent-less edit and assigns some caption to it. If this work in VCL but not in LCL - then that exactly means they are different wrt having parent. Also note that LCL is only a wrapper against some toolkit library. There are LCL over GTK+, LCL over Qt and who knows what else. Maybe you can switch LCL backend to another library and fix it. Or maybe not.Folkestone
I gave it a shot, but I cannot duplicate this issue (lazarus 0.9.30.4).Cart
I tried recreating the error on a new from scratch application, and couldn't make it happen there the way it did in the imported from delphi project either. I'm guessing it's pretty likely that perhaps that a project setting or compiler option must be different in the project I imported from Delphi.Wilbertwilborn
W
1

After further experimentation, I have been able to solve most of the immediate problem of it crashing by adding a line to set the parent of the TEdit to be the Frame (versus setting the parent of the Frame). Like so:

edTime.Parent := Self;
edTime.Text := '12:00';

But I'd still love to understand better why this is "sometimes" needed.

edit: while this fixes being able to set text on a TEdit this doesn't fix the autosizing code I have that iterates through the components and resizes any that happen to be checkboxes. Apparently the form not having it's parent set is still "sort of" a problem.

edit2: Adding a second parameter to the constructor and setting the parent for the entire form in the constructor seemed to eliminate the need to set the Parent for the TEdit's entirely.

Wilbertwilborn answered 26/9, 2012 at 15:54 Comment(1)
This is almost always required when you create a visual control (like a TEdit). It has visual content, so it needs somewhere to paint that content, and that is on the Parent.Canvas. The DFM streaming method does this automatically (and you can see the lineage or parent order of the child controls in the Structure View or by viewing the DFM as text and observing indentation levels). When you create the control in code at runtime, you have to do it yourself (as you've discovered).Monocle

© 2022 - 2024 — McMap. All rights reserved.