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?
LVL 5
scrapdogAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.