4
votes

I used the trick described in this question to display a FireMonkey form on a TPanel in a VCL application. My problem is that clicking (controls on) the embedded form causes the VCL form (containing that TPanel) to become deactivated. The most obvious consequence of that is the window border changing color all the time.

When displaying a VCL form on a TPanel of another, this doesn't happen; the forms apparently "merge". What should I do to reach a similar result with FireMonkey? I want controls on the FireMonkey form to be usable, but keep the parent form activated.

Update 1

VCL

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, FMX.Forms, Vcl.Forms,
  Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, FMX.Platform.Win;

type
  TMainForm = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

uses FireMonkeyForms;

procedure TMainForm.Button1Click(Sender: TObject);
var
  LFMForm: FireMonkeyForms.TForm1;
  LFMHWnd: HWND;
begin
  LFMForm := FireMonkeyForms.TForm1.Create(nil);
  LFMForm.Left := 0;
  LFMForm.Top := 0;
  LFMForm.Height := Panel1.ClientHeight;
  LFMForm.Width := Panel1.ClientWidth;
  LFMForm.BorderStyle := TFmxFormBorderStyle.bsNone;
  LFMForm.BorderIcons := [];
  LFMHWnd := FmxHandleToHWND(LFMForm.Handle);
  SetWindowLong(LFMHWnd, GWL_STYLE, GetWindowLong(LFMHwnd, GWL_STYLE) or WS_CHILD);
  Winapi.Windows.SetParent(LFMHWnd, Panel1.Handle);
  LFMForm.Visible := True;
end;

end.

FireMonkey

unit FireMonkeyForms;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Layouts, FMX.Memo;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Memo1: TMemo;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

end.
1

1 Answers

3
votes

The cause of the behavior is that the window manager does not know you have made your firemonkey window a child, hence it is deactivating the previously active window when you activate the firemonkey window. As is documented in SetParent function you have to set the child flag manually. An example usage could be:

var
  FMForm: TFMForm1;
  FMHWnd: HWND;
begin
  FMForm := TFMForm1.Create(nil);
  FMForm.Left := 0;
  FMForm.Top := 0;

  FMHWnd := FmxHandleToHWND(FMForm.Handle);
  SetWindowLong(FMHWnd, GWL_STYLE, GetWindowLong(FMHwnd, GWL_STYLE) or WS_CHILD);
  winapi.windows.SetParent(FMHWnd, Panel1.Handle);
  FMForm.Visible := True;

Update: If you have to remove the fmx form's borders, setting BorderStyle sets the WS_POPUP style which you cannot use with WS_CHILD. In that case set the styles you need explicitly instead of getting and 'or'ring them. F.i.

  ..
  LFMForm.BorderIcons := [];
  LFMForm.BorderStyle := TFmxFormBorderStyle.bsNone;
  LFMHWnd := FmxHandleToHWND(LFMForm.Handle);
  SetWindowLong(LFMHWnd, GWL_STYLE, WS_CHILDWINDOW or WS_BORDER);
  ..