鳥の巣箱

ネトゲしたり、機械いじったり、ソフト書いたり、山篭ったり、ギャンブルしたりする人

TImageのリサイズ時に気をつけること

Delphiやりはじめて初日ですどうも。早速躓きまくってるので色々メモ書きをガンガン残していきます。




DelphiでTImageコンポーネントを、フォームのサイズに合わせてリサイズしようとしていたのだが、どうにもうまくリサイズされない。

通常のコンポーネントは、プロパティのAlignとAnchorsを設定すればフォームの大きさに合わせて可変する。

しかし、TImageさんはフォーム起動時の大きさを維持したまま動かない。
なぜ??

最初に書いたソースの該当部分はこれ。

procedure TForm1.FormResize(Sender: TObject);
var
  //X軸Y軸開始座標格納
  XAxis, YAxis : Integer;

begin
  XAxis := 0;
  YAXis := 0;

  //キャンバスの各種描画
  with Image1.Canvas do
  begin
    //キャンバスの塗りつぶし
    brush.Color := clblack;
    fillrect(Image1.Canvas.ClipRect);

    //軸の描画
    Pen.Color := clLime;
    pen.Width := 3;
    XAxis := Image1.Height div 2;
    moveto(0,XAxis);
    lineto(Image1.Width,XAxis);
  end;

フォームのリサイズイベントハンドラにImage1.Canvasの塗りつぶしと描画を発生させている。

しかし、フォームを可変させようとコンポーネントのサイズ自体が変化しないのであればなんの意味もない。
なんでやろかと調べてたところ、TImageのCanvasプロパティは、他のコンポーネントのそれとはちょいと違うらしい。

TImageのCanvasプロパティを利用して描画をしてから表示されるまでの流れは
1.Canvasプロパティを使って描画を行おうとすると、PictureGraphicに代入されてる「TBitmap」に描画がはじまる
2.TBitmapでOnChangeイベント発生 → TImageのイベントハンドラ呼び出し
3.イベントハンドラでTImageの表示領域をInvalidateメソッドで無効化し、Windowsに再描画を要求
4.Updateメソッドで強制的に再描画。しかしWindowsからの再描画要求によってPaintメソッドが呼ばれ、Picture.Graphicに代入されているTBitmapがTImageの表示面にStretchDrawで描画される。

というメンドクサイ手順を追ってるようだ。
もともとTImageというものがPicture.Graphicに代入されている画像を表示するコンポーネントらしい。
暗黙的にTImageはTBitmapを抱えているようだ。

抱き合わせ販売とか詐欺まがいなことはやめてほしい()

つまりTBitmapのサイズをフォームに合わせてリサイズしてやり、そのサイズにあわせてTImageをリサイズさせる。
という段取りを経る必要があるようだ。

よって、上記のソースはこうなる。

procedure TForm1.FormResize(Sender: TObject);
var
  //Image_AというTbitMapダミーのコンポーネントを宣言
  //実際には表示されない
  Image_A : TBitMap;

  //X軸Y軸開始座標格納
  XAxis, YAxis : Integer;

begin
  XAxis := 0;
  YAXis := 0;

  //Image_Aを生成
  Image_A := TBitMap.Create;
  //Image_AのWidthとHeightをForm1に合わせる
  Image_A.Height := Form1.Height;
  Image_A.Width := Form1.Width;
  //Image1をImage_Aにあわせる
  Image1.Picture.Bitmap := Image_A;
  //オブジェクトの解放
  Image_A.Free;
  Image_A := nil;

  //キャンバスの各種描画
  with Image1.Canvas do
  begin
    //キャンバスの塗りつぶし
    brush.Color := clblack;
    fillrect(Image1.Canvas.ClipRect);

    //軸の描画
    Pen.Color := clLime;
    pen.Width := 3;
    XAxis := Image1.Height div 2;
    moveto(0,XAxis);
    lineto(Image1.Width,XAxis);
  end;

end;

とまぁ、これでうまく動く。
注意しなければならないのは

Image_A.Free;
Image_A := nil;

この記述を忘れると、リサイズを繰り返すうちにメモリを食い潰すことになる。(普通にフリーズする)
Image_Aというポインタがリサイズされるたびに生成され続けることになる。
TImageのリサイズが終わったタイミングで必ず開放すること。