戻る ホーム 上へ

2.12 TImage

TImage(イメージコントロール) はグラフィックスを気軽に表示できる便利なコントロールですが、同時に非常に誤解を受けやすいコントロールでもあります。この節ではまず「TImage が何か」という点から説明し、TImage の誤解されやすい点や使い方のコツを示しながら TImage の機能を解説します。

2.12.1 TImage とは何か

TImage の基本的な機能は Picture.Graphic プロパティ に代入されているグラフィックスを表示することです。Picture.Graphic プロパティ には 2.10 グラフィッククラスの作り方で説明したグラフィックスクラスのインスタンスが代入できるので、TImage はグラフィッククラスが用意されていれば原理的にどんなグラフィックスでも表示できます。

Figure 2.12-1

TImage は、表示の位置や大きさをグラフィッククラスの Draw メソッドに与えて描画を行っているだけで、実際の描画はグラフィッククラスに任せています。では TImage が何を行っているかというと、まとめると以下のようになります。

  1. グラフィックスの描画
    TImage の大きさ(Width/Height/Left/Top)、Center, Stretch, Proportional (Proportional はDelphi6のみ) プロパティ からグラフィックスの表示位置を計算し、必要に応じて Picture.Graphics に代入されているグラフィッククラスのインスタンスの Draw メソッドを呼び出し描画する。
  2. パレットの通知
    GetPalette メソッドを介して VCL にグラフィックスのパレットをしらせる。
  3. パレットの変更通知
    Picture.Graphics のパレットの変更を検出し、VCL にしらせる。
  4. グラフィックスの自動再描画
    Picture.Graphics に代入されているグラフィックスの変更を検出し自動的に再描画を行う。
  5. オフスクリーンビットマップの Canvas の提供
    Picture.Graphics に代入されているグラフィックスが TBitmap の場合、TImage の Canvas は オフスクリーンビットマップ(TBitmap) の Canvas になる。
  6. オフスクリーンビットマップの自動生成
    Picture.Graphics 空の場合に Canvas プロパティ を参照するとTImage と同じ大きさの TBitmap のインスタンスが自動的に作成され、Picture.Graphics に代入される。

5, 6 が誤解を生んでいる元凶で、TImage を OnPaint で再描画しなくてもよい TPaintBox だと単純に考えて訳が判らなくなっている方が大勢入るようです。どう違うかという点について以下の節で詳細に解説します。

2.12.2 グラフィックスの描画

繰り返し述べますが TImage がグラフィックスを表示するためのコントロールです。TImage は自分の コントロールのキャンバスにグラフィックスを StretchDraw メソッドで描画します。StretchDraw メソッドはグラフィックスクラスの Draw メソッドを呼び出して描画します。つまり描画はグラフィッククラス側の役割で TImage は位置決めと描画タイミングの面倒を見ているだけです。パレットのハンドリング(実体化)も グラフィッククラス側が担当します。

TImage の表示先の位置決めは以下のように行っています。尚、以下の説明では Delphi 6 で追加された Proportioanal プロパティが出てきますが、このプロパティは、Delphi 5 以前の TImage にはありません。Proportional = False として下記の説明をお読みください。

 
Stretch/Proportional/Center = False (デフォルト)の場合、グラフィックは、グラフィックの Width/Height プロパティの示す大きさで表示されます。もちろん、TImage からはみ出す部分は表示されません。

Stretch = False の場合 Proprtional を True にすると、グラフィックは縦横比を保ち、かつ全てが表示されるように適宜縮小されます。元の大きさ(Width/Height)より大きく表示されることはありません。

Stretch = True なら、TImage はグラフィックをTImage の大きさにあわせてできるだけ大きく表示しようとします。
Proportional = False の場合はグラフィックをイメージコントロールと同じ大きさで表示しますがグラフィックの縦横比を保ちません。
Proprtional=True の場合は縦横比を保った上で、グラフィックが全て表示可能な最も大きな大きさにグラフィックを拡大・縮小して表示します。

Center=Trueの場合、グラフィックは常にイメージコントロールの中央に表示されます。

2.12.3 パレットの通知

2.6 パレットで解説しましたように、各コントロールは GetPalette メソッドで VCL に自分が持っているパレットを通知します。TImage は  Picture.Graphic.Palette プロパティ(グラフィックスのパレット)をそのまま GetPalette の戻り値として返します。

2.12.4 パレットの変更通知

グラフィッククラスはパレットやイメージが変更されると OnChange イベントを起こします。TImage はこのイベントハンドラの中でグラフィッククラスの PaletteModified プロパティ をチェックし True なら VCL にパレットが変わった事を通知します。「通知」とは具体的にはフォームに WM_QUERYNEWPALETTE を送る事です。常に送るわけではなく

グラフィックの OnChange イベント発生時に

TImage が Visible
設計時ではない
グラフィックの PaletteModified が True
親フォームがアクティブ
親フォームのウィンドウが存在する

という条件を全てクリアされた場合だけメッセージが送られます。WM_QUERYNEWPALETTE メッセージがアクティブなフォームに届くと、全てのコントロール、ウィンドウのパレットに色が再配分されます。尚、グラフィックの PaletteModified プロパティ は TImage が自動的に False に設定します。

2.12.5 グラフィックスの自動再描画

2.12.4 でも若干触れましたが、TImage は Picture プロパティ の OnChange イベントにイベントハンドラセットします。 Picture.Graphic にグラフィッククラスが代入されると、Picture プロパティ は グラフィッククラスの OnChange イベントにハンドラをセットするので、グラフィックが変更されるとグラフィックスの OnChange イベントが Picture プロパティ を介して TImage に伝わり、TImage はグラフィックを再描画します。

2.12.6 オフスクリーンビットマップの Canvas の提供

TImage の Canvas プロパティ は他のコントロールの Canvas プロパティ とは違っています。

Canvas は普通はそのコントロールの描画面に描画するためのものですが、TImage の Canvas は Picture.Graphic に代入されている TBitmap の インスタンス(オフスクリーンビットマップ)に描画するためのものです。いいかえると、TImage の Canvas は TImage の Picture.Bitmap.Canvas とほぼ同じ物で、TImage の本来の Canvas は隠されて利用者には見えないようになっています。

「ほぼ」と書いたのは、Picture.Bitmap.Canvas をアクセスした場合と違って、Picture.Graphic に TBitmap 以外のグラフィックが入っていた場合、Canvas プロパティ を使おうとすると例外が起きるからです。つまり TImage の Canvas プロパティ はTBitmap 専用の Canvas で、それ以外のグラフィックに対しては使えません。

Canvas プロパティ を使って図形を描画してから表示するまでのストーリーは以下の様になります。

  1. Canvas プロパティ を使って描画を行うと Picture.Graphic に代入されている TBitmap に図形が描かれる。
  2. TBitmap で OnChange イベントが起こり、TImage のイベントハンドラが呼ばれる。
  3. イベントハンドラは TImage の表示領域を Invalidate メソッドで無効化し、Windows に再描画を行うように要求する。
  4. Update メソッドで強制的な再描画が促されるか、Windows からの再描画要求によって Paint メソッドが呼ばれ、Picture.Graphic に代入されている TBitmap が TImage の表示面に StretchDraw で描画される。

Canvas への描画がストレートに画面に描画されるのではなく、いったんオフスクリーンビットマップに描画され、そのビットマップ全体が適当な時期に TImage の表示面に描画されることに注意して下さい。これはけっこう「重い」処理です。また、Canvas への書き込みは TImage の表示面を「無効化」するだけで再描画はすぐには起きないことに注意して下さい。TImage の Canvas に対し複数の図形を連続して描き込んだ場合、全てが描き込まれた結果だけが表示されます。

TImage のグラフィックの再描画は描画するグラフィックによって少し様子が変わります。TImage は描画するグラフィックが TImage 全体を覆うかをチェックし、その背景を再描画するかを決めています。例えば描画する図形が透明な部分を持つ場合必ず背景が再描画されます。このため、TImage の Canvas プロパティ に頻繁に書き込みを行うとちらつきが起こってしまいます。TPaintBox のような調子でラバーバンドなどの描画を行うと激しいちらつきが起こるので注意して下さい。

2.12.7 オフスクリーンビットマップの自動生成

Canvas プロパティ にはもう一つ面白い機能が有ります。Picture.Graphic プロパティ が「空」な場合、Canvas プロパティ を使おうとすると TImage は TImage と同じ大きさの TBitmap のインスタンスを作り Picture.Graphic プロパティ に代入します。

この TImage の性質から、TImage を単に一度 Canvas で図形を書き込むと、その図形を保持しつづけるコントロールと思ってしまう方が多々おられます。間違いでは有りませんが、TImage の大きさと TBitmap の大きさが一致しないことが有るという点を理解しておかないと訳が分からなくなります。

例えば、TImage の Canvas を使って図形を書き込み、その後 TImage の大きさを変更した場合、Picture.Graphic に格納されている TBitmap の大きさは変化しません。ですから、TImage の大きさを大きくすると、Canvas で描けないエリアが出来ます。Canvas で TImage に描けるようにするには、Picture.Graphic に代入されている TBitmap を破棄して新しい大きさの TBitmap を作成し代入する必要が有ります。

TImage 内のグラフィックを破棄するには

  Image1.Picture := Nil;

とするのが最も簡単です。

2.12.8 まとめ

TImage は グラフィックを表示するためのコンポーネントです。TImage はグラフィッククラスさえ用意すれば原理的にどのようなグラフィックも表示する事が出来ます。
TImage の表示はグラフィッククラスの Draw メソッドで行われます。TImage 自体はグラフィックスを表示する機能を持ちません。
TImage はグラフィックのイメージの変更、パレットの変更を検出し、自動的にグラフィックを再描画します。
TImage の Canvas は普通の Canvas ではなく Picture.Bitmap の Canvas です。
TImage に内に グラフィックが無い場合、TImage の Canvas を参照すると自動的にTImage と同じ大きさのオフスクリーンビットマップが 作成され、Picture.Graphic プロパティ に代入されます。
TImage のサイズと Picture.Graphic プロパティ に代入されたグラフィックの大きさは独立です。TImage のサイズ変更はグラフィックの大きさを変更しません。

戻る ホーム 上へ

inserted by FC2 system