• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 279
  • Last Modified:

Embedding a form

I want to embed a form within a component I am writing.  Right now, the following code is in my Create:

FForm := TTheForm.Create(self);
FForm.Hide;
FForm.BorderStyle := bsNone;
FForm.Parent := self;
FForm.Align := alClient;
FForm.Show;


As soon as FForm.Show is called, I get the "Control '' has no parent window" exception.

I figure the constructor is a bad place to call "Show".  What would be the right place?
0
scrapdog
Asked:
scrapdog
1 Solution
 
kretzschmarCommented:
guess you call this in the oncreate of self, or?
0
 
scrapdogAuthor Commented:
It is called in Create.  (There is no OnCreate, as the component meant to be the parent is not a form)
0
 
pcsentinelCommented:
I've done a similar thing for a replacement for the TDateTimePicker

in the Create I dont set a parent at all

so

  FDrop:=TForm.Create(Self);
  FDrop.BorderStyle:=bsNone;
  FDrop.FormStyle:=fsStayOnTop;
  FDrop.ClientHeight:=170;
  FDrop.ClientWidth:=200;
  FDrop.Name:='SDatePickForm';
  FDrop.OnKeyDown:=GetDropKey;

most of the lines are irrelevant so ignore them


but I just do a show as in

FDrop.Show;


everything works fine


regards
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
scrapdogAuthor Commented:
Actually, it is necessary that I set the parent.

The reason I want to use a form in this way is because I have a bunch of buttons and other controls that need to appear inside each instance  of this component.  Rather than take the tedious route of creating them all dynamically, I'd rather do it in the form designer and then "mount" this form on the client area of the component.

(I've had no problems in the past mounting forms on other components, but in those cases, the components were already created and visible.    I am assuming that inside the constructor of a TWinControl, the control is not yet showing so this is what causes the exception...)
0
 
kretzschmarCommented:
if you has override an constructor whereas in is your code above,
did you called inherited create before?
0
 
ArhiCoderCommented:
All works fine!

procedure TForm1.FormCreate(Sender: TObject);
var
    FForm:TForm2;
begin
    FForm := TForm2.Create(self);
    FForm.Hide;
    FForm.BorderStyle := bsNone;
    FForm.Parent := self;
    FForm.Align := alClient;
    FForm.Show;
end;
0
 
scrapdogAuthor Commented:
Yes.

Here is the code in its complete context (minus the unrelated bits...):


constructor TDetailColumn.Create(AOwner: TComponent);
begin
    inherited;
   
    FForm := TBrowserForm.Create(self);
    FForm.Hide;
    FForm.BorderStyle := bsNone;
    FForm.Parent := self;
    FForm.Align := alClient;
    FForm.Show;
end;


I'm pretty sure I understand why the exception is happening, but can't think of any other place I can put FForm.Show...
0
 
scrapdogAuthor Commented:
I don't have an OnCreate in my component, ArhiCoder...however, your suggestion inspired me to try overriding AfterConstruction.  Alas, that didn't work either. :|
0
 
scrapdogAuthor Commented:
(And also, if it helps, this component will never be streamed.  It is always directly created programmatically.)
0
 
AndersonCarliCommented:
try use Application as Parent:

    FForm.Parent := Application;
0
 
tobjectpascalCommented:
procedure TForm1.Button1Click(Sender: TObject);
begin
 FForm := TForm.Create(self);
 FForm.Parent := self;
 FForm.Show;
end;


That's interesting, using Parent as the main form you produce an MDI style window, never knew that! lol. cool
0
 
kretzschmarCommented:
try this

constructor TDetailColumn.Create(AOwner: TComponent);
begin
    inherited Create(AOwner);  //concrete the inherited
   
    FForm := TBrowserForm.Create(self);
    FForm.Hide;
    FForm.BorderStyle := bsNone;
    FForm.Parent := self;
    FForm.Align := alClient;
    //FForm.Show; //leave this out, not sure, but the embedded form should be shown if the parent is shown
end;

> FForm.Parent := Application;
is not a solution, because Application is an invisible form

meikl ;-)
0
 
scrapdogAuthor Commented:
If I omit the hide/show, the exception just occurs when I assign the parent instead.
0
 
kretzschmarCommented:
well then i should try to reproduce
(can i do only this evening in some hours)
0
 
scrapdogAuthor Commented:
That would be great!  To save you some time, I created a barebones minimum project that reproduces this.  If you want, I can email it to you as well.



(For the sake of brevity, I didn't include the code for SmallFrm here since it is just a form with a button and no code.)
--------------------------------------------------------


unit MainFrm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, SmallFrm, StdCtrls, ExtCtrls;

type
  TTestComponent = class(TCustomPanel)
  protected
    FForm :TSmallForm;
  public
    constructor Create(AOwner :TComponent); override;
  end;


  TMainForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    FTest :TTestComponent;
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

{ TTestComponent }

constructor TTestComponent.Create(AOwner: TComponent);
begin
    inherited;
    FForm := TSmallForm.Create(self);
    FForm.Hide;
    FForm.BorderStyle := bsNone;
    FForm.Parent := self;
    FForm.Align := alClient;
    FForm.Show;
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
    if not assigned(FTest) then begin
        FTest := TTestComponent.Create(self);
        FTest.Align := alRight;
        FTest.Left := Width - 300;
        FTest.Parent := self;
    end;
end;

end.
0
 
kretzschmarCommented:
yes of course your panel did not have a parent

a workaround could be

constructor TTestComponent.Create(AOwner: TComponent);
begin
    inherited;
    FForm := TForm2.Create(self);  //had to recode a bit ;-))
    FForm.BorderStyle := bsNone;
    FForm.Parent := self;
    FForm.Align := alClient;
    if (AOwner is TWinControl) then
    begin
      parent := TWinControl(AOwner);
      FForm.Show;
    end;
    (* mabe additional
      else raise Exception.Create('The Owner must be a Descandend of TWinControl');
    *)
end;

meikl ;-)
0
 
scrapdogAuthor Commented:
Sweet!  Probably not the safest solution, but it works, and the only one who is going to use this component is me.

Thanks!
0
 
kretzschmarCommented:
>Probably not the safest solution
yep,  of course the check should be on the beginning,
and i'm sure there is a solution that may more comfortable

glad it was usefull for you :-))

meikl ;-)
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now