2
votes

My Delphi XE7 FireMonkey project is growing controls and naturally I've moved to using frames. Where I've used frames in the VCL there have been situations where I've simply chosen to host one (complex) VCL form inside another instead, creating and displaying it in the form's OnShow and setting it client-aligned (the benefit of this is that you don't get issues with dangling inherited controls when you edit the frame).

With FireMonkey though, things have changed slightly and my attempt to get a child form client aligned inside another is stumbling. I came across this very useful SO link which shows how to host a FireMonkey form inside a VCL form so I built on this with my code as follows:

procedure THostForm.FormCreate(Sender: TObject);
begin
  FForm := TChildForm.Create( Self );
  FForm.BorderIcons := [];
  FForm.BorderStyle := TFmxFormBorderStyle.None;
  FForm.Visible := True;
  FForm.Parent := Self;
  ResizeForm;
end;

procedure THostForm.FormResize(Sender: TObject);
begin
  inherited;
  ResizeForm;
end;

procedure THostForm.ResizeForm;
begin
  if Assigned(FForm) then
    FForm.SetBounds( Round(ClientRect.Left), Round(ClientRect.Top), Round(ClientWidth), Round(ClientHeight));
end;

This produces a child form which changes size with the host form, but remains at the top left of the screen. I've tried various position options in the ResizeForm routine too. It seems to me that a form might not be able to be the parent of another because TForm is not IAligneableControl whereas TFrame is. So, I tried 'docking' my child form to a TRectangle client aligned in the host form and this behaves the same way.

Has anyone examined this?

* SOLUTION DETAIL AS SUGGESTED BY MARCO BELOW *

Marco's solution is very neat and reduces the 'hosting' to just two lines of code. You do need to ensure that your child (hosted) form has everything inside another client aligned control - Marco suggested using a TLayout, but I already had a TPanel that I am using for a background so I had no modifications to the child form at all. So, to host this child form TChildForm inside a THostForm simply do:

procedure THostForm.FormCreate(Sender: TObject);
begin
  FForm := TChildForm.Create( Self );
  FForm.Panel1.Parent := Self;
end;

Job done. Thanks Marco.

1
Try ClientToScreen(ClientRect) or - if the parent form itself is not a child of another form - simply BoundsRect.Ondrej Kelle
Good idea - that solves the top left problem but moving the host form does not move the child - I guess because that does not trigger OnResize. The resizing looks fairly dreadful too with a flickering black band due to the repositioning.Brian Frost

1 Answers

4
votes

Mixing forms and controls in FireMonkey is not such a good idea as it is the VCL, because in the VCL controls and form are all TWinControl descendant with their own Windows handle, while in FireMoneky the form is associuated with an operating system object while the controls are not.

The address scenario, I've used a different solution. Created a form with a client-aligned, useless TLayout with all of the controls inside it. At runtime, create this form and parent the Layout to the new container (for example a tab in a multi tab control).

I've used this a few times, never found big issues with it, and a nice way to dynamically crate tab pages keeping the visual development model.