Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2022年06月23日] [更新 2022年06月25日] Delphi 一般・その他
VCL フォームアプリで FireMonkey のフォームを使用
動作確認等 Windows 10 ビルド 19043 Pro 64 bit + Delphi XE5(UP2) Pro VCL-32
Windows 10 ビルド 19043 Pro 64 bit + Delphi 10.4 Community VCL-32
[整理番号 - 1130]







VCL フォームアプリで FireMonkey のフォームを使用


VCL フォームに FireMonkey のフォームを表示するコンポーネントの紹介記事です.VCL のフォームをコンテナコントールとして,その上に FireMonkey のフォームを表示します.

VCL フォームアプリケーションは,Windows 専用のアプリ開発用です.FireMonkey には,VCL が標準では実装していないグラフィクスの機能が多くあります.VCL フォームアプリで FireMonkey のフォームが使用てできれば,間接的にそれらの機能を利用できることになります.



[FireMonkey で使えるコンポーネントは?] に掲載されてるいコンポーネントの例です.






01_TFireMonkeyContainer コンポーネントの入手とインストール


今回テストしたのは,TFireMonkeyContainer というコンポーネントです.このコンポーネントは,以下の GitHub から入手できます.今回は [Code] をクリックして ZIP 書庫をダウンロードしました.



図1
コンポーネントのダウンロード
  • 今回は ZIP 書庫をダウンロード

タウンロードした ZIP 書庫を解凍 / 展開します.フォルダ [firemonkey-container-master] を任意の場所にコピーまたは移動します.

Delphi の IDE を起動して,このフォルダにライブラリのパスを通します.[Packages] フォルダ内のプロジェクトグループファイル (拡張子は .groupproj) を開きます.今回は Delphi XE5 を使用しているので,[ファイル] [開く] から ]FireMonkeyContainer_XE5.groupproj を開きました.




図2
プロジェクトグループファイルを IDE で開く
  • フォルダ [firemonkey-container-master] にライブラリパスを通しておく

[プロジェクトマネージャ] の以下の 2 つのパッケージのプロジェクトを各々アクティブにして,マウス右ボタンクリックのメニューから [コンパイル] します.パッケージのプロジェクトをアクティブにするには,ファイル名をダブルクリックします.

// [プロジェクトマネージャ] での拡張子は,コンパイル済みの bpl)
FMXContainer_Designtime_XE5.dpk
FMXContainer_Runtime_XE5.dpk



図3
パッケージをコンパイルしてインストール
  • 2 つともコンパイルしたら
    FMXContainer_Designtime_XE5.dpk をインストール

コンパイルしたら,FMXContainer_Designtime_XE5.dpk (設計時パッケージ) をアクティブにして,マウス右ボタンクリックのメニューから [インストール] します.
[上書き保存] すればインストール作業は終了です.Delphi の IDE を閉じます.
コンポーネントパレットに [Parnassus] (パルナッソス) というタブが追加され,そこに登録されます.



図4
インストール完了

[備考]
Delphi 10.4 でライブラリパスを設定するには,[ツール] [オプション] でダイアログを表示して,左ペインを [言語] [Delphi] と展開します.そこに [ライブラリ] の項目があります.右ペインの [選択したプラットフォーム] を確認して [ライブラリパス] で設定します.





02_TFireMonkeyContainer を使用するプロジェクトの作成


メインフォームのボタンをクリックしたら,別のフォームを表示して,そこに FireMonkey のフォームを表示する,という方針でサンプルを作成してみました.

VCL フォームアプリケーションを作成したら,新規に VCL フォームを追加します.次に [プロジェクト] [プロジェクトに追加] で,既存の FireMonkey のフォームを追加します.この時,下図のダイアログが現れますが,[はい] をクリックして追加します.
この FireMonkey のフォームは,自動生成から除外して,実行時に生成すようにします.

VCL フォームアプリケーションの開発環境では,FirmeMonkey のフォームを新規に作成することはできません.その逆も同じです.




図5
FireMonkey のフォーム追加時の警告

プロジェクトのソースコードは次のようになります.



リスト1
テスト用に作成したプロジェクトファイルのソースコード
program Project1;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2},
  fmxUnit1 in '..\fmxForms\fmxUnit1.pas' {fmxForm1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.


メインフォームの設計時画面とコードです.TButton が 1 つだけのフォームです.この TButton クリックで別のフォームをモーダル表示します.




図6
メインフォームの設計時画面

リスト2
メインフォームのコード
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Unit2;

{$R *.dfm}

//=============================================================================
//  FireMonkey のフォームを表示するフォームをモーダル表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.Left := Self.Left + 50;
  Form2.Top  := Self.Top + 70;

  Form2.ShowModal;
end;

end.


下図は,メインフォームから表示するフォームの設計時画面です.
TFireMonkeyContainer コンポを配置して,その Align プロパティを alClient にします.実際には,このコンポーネントが FireMonkey フォーム表示用のコンテナです.
このコンポーネントは,[Parnassus] (パルナッソス) というタブに登録されています.




図7
子フォームの設計時画面
  • TFireMonkeyContainer コンポを配置
  • Align プロパティを alClient にする

TFireMonkeyContainer コンポーネントの,下図のイベントを実装して,FireMonkey のフォームの生成と解放処理のコードを記述します.

Delphi の IDE で FireMonkey のフォームのコードを開いている状態であれば,オブジェクト・インスペクタの FireMonkeyForm プロパティにそのフォームを選択して設定できます.しかし,この設定方法では,FireMonkey のフォームを閉じた後に再表示ができなくなります.以下のコードのように,イベントを使用した方が無難です.




図8
TFireMonkeyContainer コンポのイベント
  • FireMonkey フォームの生成と解放処理用

リスト3
メインフォームから表示するフォームのコード.uses の先頭に FMX.Forms が必要
unit Unit2;

interface

uses
  FMX.Forms, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Parnassus.FMXContainer;

type
  TForm2 = class(TForm)
    FireMonkeyContainer1: TFireMonkeyContainer;
    procedure FireMonkeyContainer1CreateFMXForm(var Form: TCommonCustomForm);
    procedure FireMonkeyContainer1DestroyFMXForm(var Form: TCommonCustomForm;
      var Action: TCloseHostedFMXFormAction);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form2: TForm2;

implementation

uses
  fmxUnit1;

{$R *.dfm}

//=============================================================================
//  FireMonkeyContainer1 の OnCreateFMXForm イベント
//  FireMonkeyForm プロパティ設定時に発生
//  FireMonkeyForm フォームが設定されていなければ生成して設定
//
//  uses に FMX.Forms と fmxUnit1 (表示するフォームのユニット名) が必要
//=============================================================================
procedure TForm2.FireMonkeyContainer1CreateFMXForm(var Form: TCommonCustomForm);
begin
  if not Assigned(Form) then begin
    fmxForm1 := TfmxForm1.Create(nil);
    Form := fmxForm1;
  end;
end;

//=============================================================================
//  FireMonkeyContainer1 の OnDestroyFMXForm イベント
//  FireMonkeyContainer1 が破棄される時に発生
//
//  uses に FMX.Forms と fmxUnit1 (表示しているフォームのユニット名) が必要
//=============================================================================
procedure TForm2.FireMonkeyContainer1DestroyFMXForm(var Form: TCommonCustomForm;
  var Action: TCloseHostedFMXFormAction);
begin
  Action := fcaFree;
  fmxForm1 := nil
end;

end.


メインフォームから  TFireMonkeyContainer コンポーネントを配置したフォームを表示する場合,以下のように FireMonkey のフォームを生成することもできます.この場合は, TFireMonkeyContainer コンポーネントのイベント処理は必要ありません.



リスト4
メインフォーム側で FireMonkey のフォームを生成する場合.uses の先頭に FMX.Forms が必要
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Unit2,
  fmxUnit1;

{$R *.dfm}

//=============================================================================
//  FireMonkey のフォームを表示するフォームをモーダル表示
//
//  fmxForm1 は [自動生成] から除外しておく
//  TFireMonkeyContainer.の FireMonkeyForm に FireMonkey のフォームを指定
//  オブジェクト・インスペクタで設定すると 2 回目以降表示しなくなる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  fmxForm1 := TfmxForm1.Create(self);
  try
    Form2.FireMonkeyContainer1.FireMonkeyForm := fmxForm1;

    Form2.Left := Self.Left + 50;
    Form2.Top  := Self.Top + 70;
    Form2.ShowModal;
  finally
    FreeAndNil(fmxForm1);
  end;
  SetActiveWindow(Handle);
end;

end.




03_作成したプログラムの実行結果
FireMonkeyContainer_TEST.zip [11.9 MB] 2022年06月25日版 (EXE同梱
Delphi 10.3 Rio / 10.4 Sydney 用パッケージ付き


下図のように,プロジェクト用のフォルダを作成してテストしています.




図9
FireMonkey のプロジェクトのファイル
  • 赤枠がフォームのファイル

下図が実行結果です.VCL フォームアプリの EXE を起動してメインフォームを表示します.メインフォームの Button1 をクリックすると Form2 に FireMonkey のフォームを表示します.表示する画像ファイルは,EXE があるフォルダの 1 つ上の階層にあると仮定しています.




図10
実行結果
  • Form1 の Button1 をクリック
  • FireMonkey のフォームが表示される

下に示すコードが FireMonkey のフォームのコードです.
TImageControl に画像を表示します.TImageControl の部分をクリックすると,ファイルの選択ダイアログが起動します.BMP / JPEG / GIF / PNG / ICO 等の画像ファイルを選択すると,その画
像を表示します.エクスプローラや他のアプリからのドラッグ・アント・ドロップにも対応しています.



リスト5
表示する FireMonkey のフォームのコード
unit fmxUnit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
  FMX.Objects;

type
  TfmxForm1 = class(TForm)
    Button1: TButton;
    ImageControl1: TImageControl;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  fmxForm1: TfmxForm1;

implementation

{$R *.fmx}

//=============================================================================
///  フォーム生成時の処理
//=============================================================================
procedure TfmxForm1.FormCreate(Sender: TObject);
var
  LFilePath : string;
begin
  LFilePath := ExpandFileName('../smail_27.bmp');
  ImageControl1.Bitmap.LoadFromFile(LFilePath);
end;

//=============================================================================
//  Application.ProcessMessages のテスト
//  2015/07/10 時点の FireMonkey Container ではエラーが発生
//  今回のテストではエラーは発生しない
//=============================================================================
procedure TfmxForm1.Button1Click(Sender: TObject);
var
  LIndex : Integer;
begin
  for LIndex := 0 to 100 do begin
    Application.ProcessMessages;
    Sleep(10);
  end;
end;

end.


[備考 1]
サイズの大きな画像の場合,TImageControl は,アスペクト比を保ったままで縮小したサイズの画像に変換して読み込みます.ビットマップ画像の透過処理は行われません.GIF 画像,PNG 画像,ICO 画像は透過表示します.
TImageControl をクリックしてもファイルの選択ダイアログを表示しないようにするには,EnableOpenDialog プロパティを False にします.

エクスプローラゃ他のアプリからのドラッグ・アンド・ドロップは,EXE を管理者権限で起動した場合は機能しません.


[備考 2]
IDE で,フォームの表示を VCL または FireMonkey に切り換えた時に,コンポーネントパレットが変化しない場合,[F12] キーを何回か押すと切り換わります.





04_コンポーネントに添付の Demo プログラム


TFireMonkeyContainer コンポーネントには Demo プログラムが 1 つだけ添付されています.そのプログラムでは,メインフォームの左側の TPageControl (VCL) だけに FireMonkey のフォームを表示しています.
下図は [TabShee2] に表示している FireMonkey のフォームです.




図11
Demo プログラム
  • 3 次元立方体の回転アニメーション

今回作成したテストプログラムでも同じことができます.下図がその実行結果です.Form2 をメインフォームとして実行しています.TFireMonkeyContainer コンポーネントの Align プロパティを alNone にして,適当な位置に配置しています.




図12
メインフォームに表示
  • Button1 と画像がある領域が
    FireMonkey のフォーム

TFireMonkeyContainer コンポーネントに添付されている Demo プログラムは,uses 部の以下の部分を修正しないとコンパイルエラーとなります.


FMXContainer
     ↓ 変更
Parnassus.FMXContainer