5

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);

Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • 1
    You need a parent window, I guess. SSCCE would help. – David Heffernan Apr 26 '14 at 20:29
  • Hi David. I know that. But how that they (Embarcadero in their article) can do it? – Gabriel Apr 26 '14 at 20:34
  • 1
    @J... - One should not set Patent in the constructor! – Gabriel Apr 26 '14 at 21:02
  • You can answer your own question rather than posting your new code in your question. – Jerry Dodge Apr 26 '14 at 21:54
  • @JerryDodge - I know. I was waiting for a possible better answer. For example why the code works in Embarcadero's article and not in my code. – Gabriel Apr 28 '14 at 09:47
  • @Altar - We should be able to duplicate the problem to be able to try and find why it's not working in your case. – Sertac Akyuz Apr 28 '14 at 18:28
  • .. that's only relevant for the 'caption' BTW. Client dimensions requires the window handle. – Sertac Akyuz Apr 28 '14 at 18:37
  • I tried your code now, had to modify some to get it compiled. Anyway setting 'caption' does not give an error, so I can't duplicate the problem. Client dimensions are another matter as I've said, it requires window handle, and the linked article does not set them. – Sertac Akyuz Apr 28 '14 at 19:06

2 Answers2

3

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;
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • 1
    If you're creating instances in CreateWindowHandle, consider destroying them in its counterpart: DestroyWindowHandle. Better use CreateWnd/WindowHandle for only things that require a window handle. – Sertac Akyuz Apr 28 '14 at 18:31
  • @SertacAkyuz - I don't understand. I have to manually free btnAssociate (and the other controls)? btnAssociate.Owner is set to Self so Self should free btnAssociate. Right? – Gabriel Apr 28 '14 at 18:40
  • You don't have to. But if your groupbox's window is recreated for whatever reason, you'll have alive buttons which you don't have any reference to, they'll be destroyed only when the groupbox is destroyed. – Sertac Akyuz Apr 28 '14 at 18:55
  • 2
    Create the buttons in OnCreate as before. Only use 'CreateWindowHandle' to set properties that require a window handle, like setting client width/height. – Sertac Akyuz Apr 28 '14 at 19:08
  • Well, my comments were just a few notes. What matters is the requirement for the handle for *some* of the operations. Please integrate yourself anything you like to the answer from the comments. – Sertac Akyuz May 06 '14 at 11:05
  • NOTE: Loaded is not a good place to do this as it is only called when the control is loaded from DFM, not also when it is created dynamically. – Gabriel Feb 27 '17 at 11:31
  • A nice source of information: https://stackoverflow.com/questions/582903 – Gabriel Nov 19 '18 at 08:13
-2

IMPORTANT: When you are creating components you need to use this lines in the constructor procedure for avoid the "Control has no parent window".

inherited Create(AOwner); parent:=TWinControl(AOwner);

  • https://stackoverflow.com/questions/6403217/how-to-set-a-tcustomcontrols-parent-in-create – Gabriel Jul 02 '19 at 07:29
  • Hello, I would use the C++Builder-6, and Delphi-7 Compiler together, because, I have to deal both with C, and Pascal files (in 32-Bit), and don't want to use ActiveX. For this, I wrote little Code Project as DLL under Windows 11 - I create a TFrame under BCB-6, and it is displayed in the Application right now at runtime, but I use TSplitter Objects in the TFrame C++ Code, which results in "Splitter1 has no parent Window. I tried to use a Package, but it seems that this does not work, here I have made some snippets what I have done so far: https://dpaste.com/BMEJ9CZ8B Thanks for helping hand. – Jens Oct 16 '22 at 03:52