今更聞けない Delphi のコト (フォームファイル編)

フォームファイルの種類

 Delphiのフォームファイルの拡張子は *.dfm ですが、同じ拡張子でも4つの種類のフォームがあります。

種類 Delphiのバージョン 説明
バイナリ形式 DFM (1) Delphi 5 以前 Delphi 4 迄はバイナリ形式 DFM しか使えない。0x80 以降の文字はコードページに依存する
バイナリ形式 DFM (2) Delphi 6 以降 Delphi 6 以降のバイナリ形式 DFM。後述の "テキスト形式 DFM (2)" をバイナリ形式にしたもの。但し、文字列はベタで格納される (Unicode-LE)。
テキスト形式 DFM (1) Delphi 5 ANSI 形式のテキスト DFM。0x80 以降の文字はコードページに依存する。
テキスト形式 DFM (2) Delphi 6 以降 ASCII 形式のテキスト DFM。0x80 以降の文字は 10進表記のコントロール文字列でエンコードされる。エンコード形式は Unicode-LE。

 バイナリ形式DFMは Delphi4 以降でも利用する事ができますが、新規プロジェクトを作成した時のフォームファイルのデフォルトはテキスト形式となります。

Delphiのバージョン デフォルトの形式 保存形式 IDEでの表示形式
Delphi4 以前 バイナリ形式DFM(1) バイナリ形式DFM(1) テキスト形式DFM(1)
Delphi5 テキスト形式DFM(1) テキスト形式DFM(1) / バイナリ形式DFM(1) テキスト形式DFM(1)
Delphi6/7 テキスト形式DFM(2) テキスト形式DFM(2) / バイナリ形式DFM(2) テキスト形式DFM(1)
Delphi2005 以降
(ガリレオIDE)
テキスト形式DFM(2) テキスト形式DFM(2) / バイナリ形式DFM(2) テキスト形式DFM(2)

 非常にややこしいのですが、このようになっています。詳しくは後程、説明します。

フォームファイルのバイナリ<->テキスト変換

 "Delphiのインストールフォルダ\bin" にある "convert.exe" を利用し、フォームファイルをバイナリ/テキストDFMに相互変換する事ができます。

 以下のコマンドはすべてのDFMファイルをテキスト形式に変換します。

convert.exe -i -s -t *.dfm

 以下のコマンドはすべてのDFMファイルをバイナリ形式に変換します。

convert.exe -i -s -b *.dfm

DFMの非互換性

 フォームに0x80以降の文字を使用している場合、"テキスト形式DFM(2)" のDFMを Delphi5 で読み込む事はできません...つまり、Delphi6以降 で作られたテキスト形式のDFMは Delphi5で 読み込めない事になります。また、Delphi6以降 で作られた バイナリ形式のDFMは Delphi5 以前で読み込む事ができません。

 バイナリ形式だろうが、テキスト形式であろうが、フォームに0x80以降の文字が使われていれば、Delphi6 とそれ以前では互換性がないという事です。例えば、Delphi5 で作ったプロジェクトを Delphi6以降 で保存してしまった場合、再度 Delphi5 で開くことはできなくなります。

 Delphi6 限定の対応策として、レジストリエントリを変更する方法があります。

[HKEY_CURRENT_USER\Software\Borland\Delphi\6.0\FileFormat]
"DFMFormat"=dword:00000000

 このように変更する事で、DFMの形式を Delphi5 互換にします...が、問題を先送りにするだけで、Delphi7 以降の互換性の問題は残ったままです。

 Delphi6 以降のDFMを Delphi5 以前で使えるようにするには、以下のようにします。

  1. もし、"バイナリ形式DFM" なら、"テキスト形式DFM(2)" に変換。
  2. "DFMコンバータ" 等を利用して、"テキスト形式DFM(2)" を "テキスト形式DFM(1)" に変換。
  3. もし、ターゲットとなる Delphi が "4以前" だったら、"バイナリ形式DFM" に変換。

コードエディタの非互換性

 Delphi6/7 では、"テキスト形式DFM(2)" が採用されていますが、IDEから "エディタで表示" した場合には、コントロール文字列が通常の文字列に変換されます(但し、コードページ依存)。そのまま日本語等を入力しても、保存されたDFMファイルをテキストエディタで開いてみると、ちゃんとコントロール文字列でエンコードされて保存されます。

 しかしながら、ガリレオIDEでは コードエディタが UTF-8 に対応しているにも関わらず、フォームファイル中の 0x80 以降の文字はコントロール文字列のまま表示されます。なおかつ、日本語等を入力するとフォームに戻そうとした時にエラーになってしまいます。日本語を含むキャプション文字列等を一括で置換したい場合には、

  1. 一旦 Delphi を閉じる。
  2. "DFMコンバータ" 等で "テキスト形式DFM(1)" に変換。
  3. 任意のテキストエディタで編集。
  4. "DFMコンバータ" 等で "テキスト形式DFM(2)" に再変換。
  5. Delphi を起動。

 と、かなり面倒な手順を踏む必要があります。

 そこで、(毎度毎度の手前味噌ですが) "DFMコンバータ エキスパート" を使います。 "DFMコンバータ エキスパート" はIDE機能拡張型のアプリケーションで、フォームファイル中のコントロール文字列をデコードして "テキスト形式DFM(1)" にし、そのまま日本語等で編集する事が可能になります。 編集後は、逆にフォームファイル中の 0x80 以降の文字をコントロール文字列にエンコードし、"テキスト形式DFM(2)" にする事ができます。

DFM のデフォルトプロパティの問題

 フォームのプロパティがデフォルトの値と同じ場合には、DFM に値が格納されません。フォームのプロパティがデフォルトの値と異なる場合のみ、DFM に値が保存される事になります。しかしながら、このデフォルト値が Delphi のバージョンによって異なる事があるため、面倒な問題を引き起こす事があります。

 ・Font
 Font は Delphi 2005 またはそれ以降で、Tahoma に変更されています。日本語版の場合、以前は "MS Pゴシック" でした。プロパティがデフォルト値と同じであっても異なっていても DFM へ保存されるため、通常は問題になる事はありません。問題になるのは、フォームを動的に生成している場合です。この場合には明示的にフォントを指定しなくてはなりません。

program Project1;

uses
  Windows,
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;

  with Application.DefaultFont do
    begin
      Name    := 'MS Pゴシック';
      Size    := 9;
      Charset := SHIFTJIS_CHARSET;
    end;

  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

 Application.DefaultFont をこのように設定し、各フォームの ParentFont を True にする 事で対処できます。

 ・Position
 Position は Delphi 2005 またはそれ以降で、poDefaultPosOnly に変更されています。以前は poDesigned でしたが、この値にしている事はまずない (していたとしても、フォームの位置をコードで指定する事が多いため) ので、そう問題になる事はないと思います。

 ・TLabel.Transparent
 Transparent は Delphi 2007 またはそれ以降で True に変更されています。真にやっかいな問題を抱えているのはこのプロパティです。

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  for i:= 0 to ComponentCount-1 do
    if (Components[i] is TLabel) then
      (Components[i] as TLabel).Transparent := True; // または False
  ...
end;

 無用な混乱を防ぐためには、各フォームの OnCreate の先頭で "プロジェクトが意図するデフォルトの Transparent プロパティ" を指定した上で、個々の Transparent プロパティをコードで明示的に指定する必要があります。

 ・TPanel.ParentBackground
 ParentBackground はデフォルトで True です。Delphi 2005 以前では Color プロパティを変更してパネルの色を変更しても ParentBackground は True のままでしたが、2006 以降では False になります。逆に ParentBackground が True だと Color での色変更は無効になります。つまり、Delphi 2005 以前で作成したパネルの色を変更したフォームを 2006 以降で読み込ませると、色の指定が無効になってしまいます。 解決策は地道に ParentBackground を False に変更するか、TLabel.Transparent と同じようにフォーム作成時に ParentBackground := False で初期化してしまうか、です。

補足


 BACK