戻る ホーム 上へ 進む

2.11 TPicture

Delphi を使いはじめた時、私が真っ先に使ったのがイメージコントロールでしたが、イメージコントロールの保持するグラフィックスにアクセスするのに

Image1.Picture.Graphic
Image1.Picture.Bitmap

などと長たらしく書かねばならないのが不満でした。この Picture Property の型が TPicture なのですが、何故このように2段階でグラフィックにアクセスしなければならないのか最初は判りませんでした。しかし使ってゆくうちに、イメージコントロールがさまざまなグラフィックデータを保持して表示するために、TPicture が重要な役割を果たしていることが判ってきました。本節では TPicture が提供するさまざまな機能を解説します。

2.11.1 TPicture の提供する機能

TPicture が提供する機能は以下の通りです。

  1. グラフィックをファイルと入出力します。(LoafFromFile/SaveToFileメソッド)
  2. グラフィックをクリップボードと入出力します。(LoadFromClipboardFormat/SaveToClipboardFormat メソッド)
  3. グラフィックをフォームファイルと入出力します。(DefineProperties/ReadData/WriteData メソッド)
  4. TPicture が扱えるクリップボード形式を管理します。(RegisterClipboardFormat メソッド)
  5. TPicture が扱えるグラフィックファイルの拡張子を管理します。(RegisterFileFormat/RegisterFileFormatRes メソッド)

1, 2, 3 の機能は TGraphic の継承クラスの持つ同名のメソッドとほぼ同じ機能です。しかし、ファイル、クリップボードからグラフィックデータを読む場合、TGraphic の継承クラスのメソッドでは、予め読み込むデータのフォーマットが判っていますが、TPicture のメソッドではどのようなグラフィックを読み込むか予め決まっていません。TPicture はファイルの拡張子や、クリップボードの識別子でグラフィックデータのフォーマットを判別し読み込みます。つまり、言い換えれば TPicture は読み込むグラフィックデータの種類に応じて適切なグラフィッククラスのインスタンスを作成し、そのインスタンスのデータ読み込み用のメソッドを呼び出してグラフィックデータを読み込むのです。

4, 5 は TPicture がグラフィックの読み込む時、グラフィッククラスを決定するための情報を管理するのに使います。

2.11.2 ファイルとの入出力

TPicture の SaveToFile メソッドは TPicture の Graphic Property に格納されているグラフィックスをファイルに書き出します。SaveToFile メソッドは Graphic Property に格納されている TGraphic 型の継承クラスのオブジェクトの SaveToFile メソッドを呼び出すだけです。

TGraphic 型とは異なり TPicture 型はストリームにグラフィックを書いたり、ストリームからグラフィックを読み込む機能はありません。ストリームからの入力ではグラフィックの種類を判定するのが困難だからです。

TPicture の LoadFromFile メソッドはファイルの拡張子を使ってグラフィックファイルの種類を判定します。例えば拡張子が ico ならアイコンファイルだと判定します。TPicture の LoadFromFile メソッドはファイルの拡張子から適切なグラフィッククラス(TBitmap, TMetafile, TIcon 等)のインスタンスを作成し、インスタンスの LoadFromFile メソッドを呼び出してグラフィックファイルの内容を読み込んで、出来上がったインスタンスを Graphic Property にセットします。

TPicture が扱えるグラフィッククラスは、Graphics ユニット内 にある FileFormatList に格納されています。FileFormatList の構造を以下に示します。

Figure 2.11-1

図2.11-1 FileFormatList変数

FileFormatList には予め3個のファイルフォーマット(TBitmap, TIcon, TMetafile)が登録されています。例えば TBitmap のファイルフォーマットでは、クラス参照には TBitmap、拡張子には 'bmp' がセットされています。

ファイルフォーマットの中の「フィルタの説明」は、グラフィックファイルのオープンダイアログに表示されるフィルタの説明です。例として下図にスピードボタンのGlyph(TBitmap)のプロパティエディタのダイアログを示します。

Figure 2.11-2

図2.11-2 Glyph(TBitmap)のダイアログ

「フィルターの説明」によく似た「フィルターの説明のリソースID」は、フィルタの説明をリソースの中に置く場合に使われます。

特定のグラフィッククラスのフィルターの説明を取り出すには Graphic ユニット内には GraphicFilter 関数が使われます。GraphicFilter はグラフィック型に対応するファイルフォーマットの「フィルターの説明」が空で、「フィルターの説明のリソースID」が0でない場合はリソースからフィルターの説明を取り出します。この機能はもちろん、フィルターの説明をリソースの中におくことによって簡単に交換可能にして、修正や国際化を簡単にするのに利用されます。

TPicture 型の Property は、特定のグラフィック型ではなく、全てのグラフィック型を格納可能な Property です。TPicture 型の Property にも設計時にグラフィックを読み込むことができます。下図はイメージコントロールの Picture Property のダイアログです。

Figure 2.11-3

図2.11-2 Picture Property のダイアログ

ファイルフォーマットリスト中の全ての拡張子が並んでいることに注意してください(*.dib は私が自作した TNkDIB 型のグラフィックの拡張子です)。これは実は GraphicFilter 関数に TGraphic をパラメータとして与えた時の結果です。このように FileFormatList はグラフィッククラスのフィルタの説明を作るのにも利用されます。

FileFormatList には TPicture のクラスメソッド RegisterFileFormat/RegisterFileFormatRes でファイルフォーマットを追加することが出来ます。パラメータの詳細はヘルプを見てください。独自の グラフィッククラスを新設した場合、グラフィックファイルの拡張子とフィルタの説明を VCL に登録できます。具体的な使い方は、2.10 グラフィッククラスの作り方2.10.12 初期化見てください。RegisterFileFormat と RegisterFileFormatRes の違いは、フィルターの説明を文字列で指定するか、リソースIDで指定するかだけです。

尚、同じ拡張子を重複して登録した場合、後から追加した方が優先するため、例えば、拡張子が bmp のビットマップファイルを独自に作成したグラフィッククラスに読み込むことができます。

2.11.3 クリップボードとの入出力

Clipboard.Assign(TPicture のインスタンス);
TPicture のインスタンス.Assign(Clipboard);

というふうに代入が行われる時、TPicture の LoadFromClipboardFormat と SaveToClipBoardFormat が Clipborad の Assign や AssignTo メソッドを介して呼び出されます。

TPicture の SaveToClipboardFormat は単純に Graphic Property の SaveToClipboardFormat を呼び出すだけですが、LoadFromClipboardFormat はなかなか面白い動きをします。

LoadFromFile の時と同様、Graphic ユニット内にはクリップボードフォーマットとグラフィック型の対応を決定するために ClipboardFormatList をもっています。ClipboardFormatList の構造を以下に示します。

Figure 2.11-4

図2.11-1 ClipboardFormatList変数

ClipboardFormatList の構造は FileFormatList に比べて簡単で、グラフィッククラスのクラス参照とクリップボード形式の識別子との対応が入っているだけです。例えば、CF_BITMAP は TBitmap、CF_METAFILEPICT は TMetafile、CF_ENHMETAFILE は TMetafile が対応しています。VCL に予め登録されているのはこれが全てです。

TPicture のインスタンス.Assign(Clipboard); という形式の代入では、ClipBoard のAssignTo メソッドが呼び出されます。AssignTo メソッドは ClipBoard の AssignToPicture メソッドを呼び出します。このメソッドの処理の概要は以下の通りです。

  Format := クリップボード上の最初のクリップボード形式;

  while Format <> 0 do begin
    Format 形式のクリップボードデータを読むことが出来るか 
                  TPicture に尋ねる;
    if 読める then begin
      TPicture の インスタンスの LoadFromClipBoardFormat を呼ぶ;
      Exit;
    end;
    Format := クリップボード上の次のクリップボード形式;
  end;

上記のループの中で、TPicture は特定のクリップボード形式が読めるかを尋ねられますが、TPicture は ClipboardFormatList を見て読めるかを答えます。もちろんリストに無かったら No と答えるわけです。

以上の処理により、クリップボード上のデータのうち、TPicture が読める最初の形式が発見されると TPicture のインスタンスは適切なグラフィッククラスのインスタンスを作成し、クリップボードデータを読み込んで Graphic Property にセットします。クリップボード上に複数のグラフィックデータがあった場合、どの形式が取り込まれるかは判りません。これは TPicture の深刻な欠点です。

それではクリップボードからデータ形式を指定して読み込むことは出来るのでしょうか? 答えは制限付きで Yes です。2.10 グラフィッククラスの作り方2.10.11 LoadFromClipboardFormat、SaveToClipboardFormat メソッド でも書きましたが、クリップボード形式を指定して読み込めるのは Assign メソッドで、TClipboard の代入を許しているグラフィッククラスだけです(2.10.10 グラフィックのコピー参照)。なぜなら、TClipboard の AssignTo メソッドが以下のように実装されているからです。以下に TClipboard の AssignTo メソッドのコードを引用します。

procedure TClipboard.AssignTo(Dest: TPersistent);
begin
  if Dest is TPicture then
    AssignToPicture(TPicture(Dest))
  else if Dest is TBitmap then
    AssignToBitmap(TBitmap(Dest))
  else if Dest is TMetafile then
    AssignToMetafile(TMetafile(Dest))
  else inherited AssignTo(Dest);
end;

一目瞭然ですが、AssignTo メソッドは TBitmap と TMetafile を特別扱いしています。クリップボード上のデータ形式と Assign 先(Dest) の型を ClipBoardFormatList を使って突き合わせ、適切なクリップボードデータをクリップボードより取り出し,Assign 先の LoadFromClipboardFormat メソッドに渡すようにすることはたやすいことですが、何故かそうはなっていません。TGraphic の多態性を活かしていない残念な実装になってしまっています。これは、ファイルの読み出し(LoadFromFile)が多態性をうまく使っているのと対象的です。改善を望みます。

ClipboardFormatListには TPicture のクラスメソッド RegisterClipboardFormat でクリップボードフォーマットを追加することが出来ます。パラメータの詳細はヘルプを見てください。独自の グラフィッククラスを新設した場合、クリップボードファイルの識別子とそれを処理できるグラフィッククラスとの対応を VCL に登録できます。具体的な使い方は、2.10 グラフィッククラスの作り方2.10.12 初期化見てください。

2.11.4 フォームファイルとの入出力

TPicture 型の定義を見ると判りますが、TPicture には Published な Property がありません。TPicture 内のフォームファイルと入出力するべきデータは Graphic property の中身ですが、Graphic Property は Published ではありません。これは、Graphic Property の中身が TGraphic 型ではなく、TGraphic の派生クラスであり、型が決まっていないからです。VCL のストリーミング機構はこのような型の定まらない Property を扱えません。

このため TPicture は DefinePropeties メソッドで 偽 Property 'Data' を定義してこれに対処しています。'Data' 偽 Property の入出力を担当するのは、TPicture の ReadData/WriteData メソッドで、WriteData メソッドはフォームファイルに

グラフィッククラスの名前 + グラフィックデータ

の形式でデータを書き込みます。グラフィックデータの部分の書き込みは グラフィッククラスの SaveToStream メソッドを利用します。ReadData メソッドはフォームファイルからグラフィッククラス名を読み取り、グラフィッククラスのインスタンスを作成してから、その LoadFromStream メソッドを呼び出し、出来上がったオブジェクトを Graphic Propety にセットします。

'Data' 偽 Property の処理の特徴は、継承フォームが使われている場合、元のフォームと継承フォームとで同じグラフィックデータをフォームファイルに書き込まないように工夫されていることです。グラフィックデータはデータ量が大きいことがありますから、後でビットマップなどをフォームファイルからロードする時に速度の大幅な向上が期待できますします。グラフィックデータが同じかをチェックするために TGraphic の Equals メソッドが使われています。

2.11.5 まとめ

TPicture はイメージコントロールの Picture property を実現するための型です。Picture Property にはさまざまなグラフィッククラスのデータを格納することが出来ます。

TPicture は LoadFromFile メソッドでさまざまな種類のグラフィックを読むことが出来ます。グラフィックの種類は拡張子で自動的に判別されます。

TPicture はクリップボードにグラフィックデータを送ったり、クリップボードからグラフィックデータを受け取ることが出来ます。但し、クリップボード上に複数のグラフィックデータがある場合受け取るグラフィックデータを指定することはできません。 TPicture とは関係ありませんが、クリップボードから指定したグラフィックデータを受け取ることが出来るのは TBitmap と TMetafile だけです。

TPicture 型の Property を持つコントロールは、設計時にさまざまなグラフィックデータを読み込み保持することが出来ます。

TPicture 型が扱えるグラフィックの種類は、RegisterFileFormat/RegisterFileFormatRes/RegisterClipboardFormat で増やすことが出来ます。

戻る ホーム 上へ 進む

inserted by FC2 system