Search code examples
delphidelphi-xe

"Control '' has no parent window" error


I get this error when I drop my control on a form. The error appears here:

  TAssociateFileExt = class(TGroupBox)
  private
  protected
  public
    btnAssociate   : TButton;
    constructor Create(aOwner: TComponent); override;
  end;

constructor TAssociateFileExt.Create(aOwner: TComponent);
begin
 inherited Create(aOwner);
 Caption:= '';                       <-------- error here
 ClientHeight:= 125;                 <-------- and here
 ClientWidth := 170;
 DoubleBuffered:= TRUE;

 btnAssociate:= TButton.Create(Self);
 btnAssociate.Parent:= Self;
 btnAssociate.Visible:= TRUE;
 btnAssociate.Left:= 17;
 btnAssociate.Top:= 26;
 btnAssociate.Width:= 142;
 btnAssociate.Height:= 25;
 btnAssociate.Hint:= 'Associate this application with its files. When you double click a file this program will automatically start and load that file.';
 btnAssociate.Caption:= 'Associate';
 btnAssociate.DoubleBuffered:= TRUE;
 btnAssociate.ParentDoubleBuffered:= FALSE;
 btnAssociate.TabOrder:= 0;
 btnAssociate.OnClick:= btnAssociateClick;

 btnAssociateDel:= TButton.Create(Self);
 btnAssociateDel.Parent:= Self;
 btnAssociateDel.Visible:= TRUE;
 btnAssociateDel.Left:= 17;
 btnAssociateDel.Top:= 53;
 btnAssociateDel.Width:= 142;
 btnAssociateDel.Height:= 25;
 btnAssociateDel.Hint:= 'Remove association';
 btnAssociateDel.Caption:= 'Remove association';
 btnAssociateDel.DoubleBuffered:= TRUE;
 btnAssociateDel.ParentDoubleBuffered:= FALSE;
 btnAssociateDel.TabOrder:= 1;
 btnAssociateDel.OnClick:= btnAssociateDelClick;

 chkAllUsers:= TCheckBox.Create(Self);
 chkAllUsers.Parent:= Self;
 chkAllUsers.Visible:= TRUE;
 chkAllUsers.Left:= 31;
 chkAllUsers.Top:= 97;
 chkAllUsers.Width:= 115;
 chkAllUsers.Height:= 17;
 chkAllUsers.Hint:= 'Please note that if you want to do this for all users then you need administrator/elevated rights.';
 chkAllUsers.Caption:= 'Do this for all users';
 chkAllUsers.DoubleBuffered:= TRUE;
 chkAllUsers.ParentDoubleBuffered:= FALSE;
 chkAllUsers.TabOrder:= 2;
 chkAllUsers.OnClick:= chkAllUsersClick;
end;

Probably the answer is 'Caption needs a valid window handle'. Right? However, an article by David Intersimone (here) says it is ok to set Caption in the constructor.

  1. Is the article wrong?
  2. Should I move the code (Caption and TButton.Create) in CreateWnd (since AfterConstruction is not a good place)? The thing is that CreateWnd can be called more than once: "CreateWnd is called automatically when the control is first created or when the underlying screen object must be destroyed and recreated to reflect property changes."

Update:
After adding (aOwner: TComponent), as J... suggested, to constructor's declaration (in Implementation) the error moved to the next line (clientheight:= 90);


Solution

  • I moved the code in CreateWindowHandle. Now it works. Full code:

    UNIT cAssociateExt;
    
    INTERFACE
    
    USES
      Windows, Messages, SysUtils, Classes, Controls, ExtCtrls, Forms, StdCtrls;
    
    TYPE
      TAssociateFileExt = class(TGroupBox)
      private
      protected
      public
        btnAssociate   : TButton;
        btnAssociateDel: TButton;
        chkAllUsers    : TCheckBox;
        constructor Create(aOwner: TComponent); override;
        procedure AfterConstruction;  override;
        procedure CreateWindowHandle(const Params: TCreateParams); override;
        ...
      published
      end;
    
    
    procedure Register;
    
    
    IMPLEMENTATION
    
    
    procedure TAssociateFileExt.AfterConstruction;
    begin
     inherited;         //Not a good place here
    end;
    
    
    procedure TAssociateFileExt.CreateWindowHandle(const Params: TCreateParams);
    begin
     inherited;
    
     //DO NOT CREATE CONTROLS HERE! See: Sertac Akyuz's comment
    
     Caption:= '';    
     ClientHeight:= 125;
     ClientWidth := 170;
    end;
    
    
    
    constructor TAssociateFileExt.Create(aOwner: TComponent);
    begin
     inherited Create(aOwner);
     DoubleBuffered:= TRUE;
    
     btnAssociate:= TButton.Create(Self);
     btnAssociate.Parent:= Self;
     btnAssociate.Visible:= TRUE;
     btnAssociate.Left:= 17;
     ...
    end;