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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With