TPicture と TStringList のカプセル化

参照元1  参照元2


redball.gif目次へ戻る

会社のロゴマークやアプリケーションアイコンなど、アプリケーションが実行中ずっと画像を保持していたいときがある。また、同様に、テキストを保持していたいときもある。このようなとき、TImage コンポーネントを使って設計時に画像を読み込んだり、TMemoTRichEdit を使って同様に設計時に読み込んでおくことにより、コンパイルしてできた exe ファイルに画像やテキストが取り込まれて実行ファイルとしての独立性が高まる。このような目的で非可視にした TImageTMemo を使うのは、まったく不合理でプログラマとしては気持ち悪い。かと言って、動的に TBitmapTJpegImageTStringList のインスタンスを作って、外部ファイルを読み込むのはどんな環境でも実行時にこの外部ファイルが必要になり、 exe ファイルの独立性がなくなったり、インスタンスの管理がやっかいだったりする。ちょっと、やってみよう。

List 1

unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, Jpeg, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject);
  private
    { Private 宣言 }
  public
    JPG:TJpegImage;
    SL:TStringList;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  JPG := TJpegImage.Create;
  JPG.LoadFromFile('C:\Home\Appl\Delphi5p\white.jpg');
  PaintBox1.Width := JPG.Width;
  PaintBox1.Height := JPG.Height;

  Label1.AutoSize := false;
  Label1.WordWrap := true;

  SL := TStringList.Create;
  SL.LoadFromFile('C:\Home\Appl\Delphi5p\花と私.txt');
  Label1.Caption := SL.Text;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  JPG.Free;
  SL.Free;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  PaintBox1.Canvas.Draw(0,0,JPG);
end;

end.
n00501.bmp

実行時の様子を右図にしめす。ここでは、FormCreate イベントハンドラで TForm1public 部のフィールド変数である TJpegImage クラスと TStringList クラスのインスタンスを作成し、jpg 画像を外部ファイルから読み込み、PaintBox1OnPait イベントハンドラで表示している。同様に、テキストは TStringList のインスタンスが外部ファイルから読み込みLabel1.Caption にセットしている。そして、これらのインスタンスは FormDestroy イベントハンドラで破棄している。


このような方式では、コード量が多くなることはもちろんだがインスタンス管理もしっかりやらなくてはならない。また、繰り返しになるが、実行時に画像とテキストのファイルが必要になる。TBitmapTJpegImage、TIcon、TMetafile などのグラフィックを保持するために使う TGraphic コンテナとしての TPicture クラスと、テキストを保持する TStringList をカプセル化したコンポーネントをつくるとこのような不便さは解消される。以下にそれらのコンポーネントのユニットファイルの全コードを示す。

List 2

unit CPictureUnit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Jpeg;

type
TCPicture = class(TComponent)
private
  FPicture: TPicture;
  procedure SetPicture(const Value: TPicture);
public
  constructor Create(AOwner: TComponent);override;
  destructor Destroy; override;
published
  property Picture: TPicture read FPicture write SetPicture;
end;

TCStringList = class(TComponent)
private
  FStringList:TStringList;
  procedure SetStringList(const Value: TStringList);
public
  constructor Create(AOwner: TComponent);override;
  destructor Destroy;override;
published
  property Strings:TStringList read FStringList write SetStringList;
end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples',[TCPicture,TCStringList]);
end;

{ TCPicture }

constructor TCPicture.Create(AOwner: TComponent);
begin
  inherited;
  FPicture := TPicture.Create;
end;

destructor TCPicture.Destroy;
begin
  FPicture.Free;
  inherited;
end;

procedure TCPicture.SetPicture(const Value: TPicture);
begin
  FPicture.Assign(Value);
end;

{ TCStringList }

constructor TCStringList.Create(AOwner: TComponent);
begin
  inherited;
  FStringList := TStringList.Create;
end;

destructor TCStringList.Destroy;
begin
  FStringList.Free;
  inherited;
end;

procedure TCStringList.SetStringList(const Value: TStringList);
begin
  if Assigned(Value) then FStringList.Assign(Value);
end;

end.

これをインストールすると、コンポーネントパレットに TCPictureTCStringList という二つの非可視コンポーネントが現れる。これらを使って、上と同じことをしてみよう。以下にその全コードを示す。

List 3

unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, CPictureUnit, jpeg;

type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    Label1: TLabel;
    CPicture1: TCPicture;
    CStringList1: TCStringList;
    procedure FormCreate(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public  宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  PaintBox1.Width := CPicture1.Picture.Width;
  PaintBox1.Height := CPicture1.Picture.Height;

  Label1.AutoSize := false;
  Label1.WordWrap := true;

  Label1.Caption := CStringList1.Strings.Text;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  PaintBox1.Canvas.Draw(0,0,CPicture1.Picture.Graphic);
end;

end.

実行時の様子は上とまったく同じである。このように、設計時に画像やテキストをオブジェクトインスペクタを使って設定しておくと exe ファイルに取り込まれて、実行ファイルとしての独立性が高まると同時に、コードも簡潔になり、インスタンスの管理も自動的に行われる。とっても便利!!

しかし、参照元のコメントにあるように、ウィンドウズのプログラム作成法の標準的な手続きとしては、実はプログラムが使う画像やテキストは、本来、リソースファイルをつくってコンパイル時にリンクして exe ファイルに取り込み、必要に応じてコードにより取り出して使うものなのである。これについては、稿をあらためてやや詳しく調べる予定である。

redball.gif目次へ戻る