问题
I want to create my own custom control. Let's say I want to initialize its graphic properties. Obviously I cannot do that in Create because a canvas/handle is not YET allocated. The same if my custom control contains a subcomponent (and I also set its visual properties).
There are quite several places on SO that discuss the creation of a custom control. They don't really agree on it.
So, I did this test that shows the creation order. The conclusion is:
Dropping control on a form:
Create
AfterConstruction
SetParent
CreateWnd
CreateWindowHandle
CreateWnd (post inherited)
SetParent (post inherited)
Executing the program
Create
AfterConstruction
SetParent
SetParent (post inherited)
SetParent
SetParent (post inherited)
Loaded
CreateWnd
CreateWindowHandle
CreateWnd (post inherited)
SetParent
SetParent (post inherited)
Dynamic creation
Create
AfterConstruction
Reconstructing the form
Not tested yet
I used to create the subcomponent in Create and set MySubcomponents.Parent = self in CreateWnd. But that is not a good place because CreateWnd is not always called. AfterConstruction is also out of question because the handle is not ready yet.
UNIT cvTester;
{This file tests the initialization order of a custom control.}
INTERFACE
{$WARN GARBAGE OFF}
USES
System.SysUtils, System.Classes, vcl.Controls, vcl.Forms, Vcl.ExtCtrls;
TYPE
TCustomCtrlTest = class(TPanel)
private
protected
public
constructor Create(AOwner: TComponent); override;
procedure Loaded; override;
procedure AfterConstruction; override;
procedure CreateWnd; override;
procedure CreateWindowHandle(const Params: TCreateParams); override;
procedure WriteToString(s: string);
published
end;
procedure Register;
IMPLEMENTATION
USES System.IOUtils;
procedure Register;
begin
RegisterComponents('mine', [TCustomCtrlTest]);
end;
constructor TCustomCtrlTest.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
WriteToString('Create'+ #13#10);
// Create other subcomponents here:
// Subcomponent.Owner:= Self;
end;
procedure TCustomCtrlTest.Loaded;
begin
inherited;
WriteToString('Loaded'+ #13#10);
end;
procedure TCustomCtrlTest.AfterConstruction;
begin
inherited;
WriteToString('AfterConstruction'+ #13#10);
end;
procedure TCustomCtrlTest.CreateWnd;
begin
inherited;
WriteToString('CreateWnd'+ #13#10);
// Subcomponent.Parent = Self;
end;
procedure TCustomCtrlTest.CreateWindowHandle(const Params: TCreateParams);
begin
inherited CreateWindowHandle(Params);
WriteToString('CreateWindowHandle'+ #13#10);
end;
procedure TCustomCtrlTest.SetParent(AParent: TWinControl);
begin
WriteToString('SetParent'+ #13#10);
inherited SetParent(AParent);
WriteToString('SetParent (post inherited)'+ #13#10);
end;
function GetAppDir: string;
begin
Result:= ExtractFilePath(Application.ExeName);
end;
procedure TCustomCtrlTest.WriteToString(s: string);
begin
System.IOUtils.TFile.AppendAllText(GetAppDir+ 'test.txt', s);
end;
end.
来源:https://stackoverflow.com/questions/56859524/where-to-initialize-subcomponent-parent