2.12 TImageTImage(イメージコントロール) はグラフィックスを気軽に表示できる便利なコントロールですが、同時に非常に誤解を受けやすいコントロールでもあります。この節ではまず「TImage が何か」という点から説明し、TImage の誤解されやすい点や使い方のコツを示しながら TImage の機能を解説します。 2.12.1 TImage とは何かTImage の基本的な機能は Picture.Graphic プロパティ に代入されているグラフィックスを表示することです。Picture.Graphic プロパティ には 2.10 グラフィッククラスの作り方で説明したグラフィックスクラスのインスタンスが代入できるので、TImage はグラフィッククラスが用意されていれば原理的にどんなグラフィックスでも表示できます。 TImage は、表示の位置や大きさをグラフィッククラスの Draw メソッドに与えて描画を行っているだけで、実際の描画はグラフィッククラスに任せています。では TImage が何を行っているかというと、まとめると以下のようになります。
5, 6 が誤解を生んでいる元凶で、TImage を OnPaint で再描画しなくてもよい TPaintBox だと単純に考えて訳が判らなくなっている方が大勢入るようです。どう違うかという点について以下の節で詳細に解説します。 2.12.2 グラフィックスの描画繰り返し述べますが TImage がグラフィックスを表示するためのコントロールです。TImage は自分の コントロールのキャンバスにグラフィックスを StretchDraw メソッドで描画します。StretchDraw メソッドはグラフィックスクラスの Draw メソッドを呼び出して描画します。つまり描画はグラフィッククラス側の役割で TImage は位置決めと描画タイミングの面倒を見ているだけです。パレットのハンドリング(実体化)も グラフィッククラス側が担当します。 TImage の表示先の位置決めは以下のように行っています。尚、以下の説明では Delphi 6 で追加された Proportioanal プロパティが出てきますが、このプロパティは、Delphi 5 以前の TImage にはありません。Proportional = False として下記の説明をお読みください。
2.12.3 パレットの通知2.6 パレットで解説しましたように、各コントロールは GetPalette メソッドで VCL に自分が持っているパレットを通知します。TImage は Picture.Graphic.Palette プロパティ(グラフィックスのパレット)をそのまま GetPalette の戻り値として返します。2.12.4 パレットの変更通知グラフィッククラスはパレットやイメージが変更されると OnChange イベントを起こします。TImage はこのイベントハンドラの中でグラフィッククラスの PaletteModified プロパティ をチェックし True なら VCL にパレットが変わった事を通知します。「通知」とは具体的にはフォームに WM_QUERYNEWPALETTE を送る事です。常に送るわけではなく グラフィックの OnChange イベント発生時に
という条件を全てクリアされた場合だけメッセージが送られます。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 プロパティ を使って図形を描画してから表示するまでのストーリーは以下の様になります。
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 まとめ
|