会社のロゴマークやアプリケーションアイコンなど、アプリケーションが実行中ずっと画像を保持していたいときがある。また、同様に、テキストを保持していたいときもある。このようなとき、TImage コンポーネントを使って設計時に画像を読み込んだり、TMemo や TRichEdit を使って同様に設計時に読み込んでおくことにより、コンパイルしてできた exe ファイルに画像やテキストが取り込まれて実行ファイルとしての独立性が高まる。このような目的で非可視にした TImage や TMemo を使うのは、まったく不合理でプログラマとしては気持ち悪い。かと言って、動的に TBitmap や TJpegImage や TStringList のインスタンスを作って、外部ファイルを読み込むのはどんな環境でも実行時にこの外部ファイルが必要になり、 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.
実行時の様子を右図にしめす。ここでは、FormCreate イベントハンドラで TForm1 の public 部のフィールド変数である TJpegImage クラスと TStringList クラスのインスタンスを作成し、jpg 画像を外部ファイルから読み込み、PaintBox1 の OnPait イベントハンドラで表示している。同様に、テキストは TStringList のインスタンスが外部ファイルから読み込みLabel1.Caption にセットしている。そして、これらのインスタンスは FormDestroy イベントハンドラで破棄している。
このような方式では、コード量が多くなることはもちろんだがインスタンス管理もしっかりやらなくてはならない。また、繰り返しになるが、実行時に画像とテキストのファイルが必要になる。TBitmap や TJpegImage、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.
これをインストールすると、コンポーネントパレットに TCPicture と TCStringList という二つの非可視コンポーネントが現れる。これらを使って、上と同じことをしてみよう。以下にその全コードを示す。
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 ファイルに取り込み、必要に応じてコードにより取り出して使うものなのである。これについては、稿をあらためてやや詳しく調べる予定である。