会社のロゴマークやアプリケーションアイコンなど、アプリケーションが実行中ずっと画像を保持していたいときがある。また、同様に、テキストを保持していたいときもある。このようなとき、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 ファイルに取り込み、必要に応じてコードにより取り出して使うものなのである。これについては、稿をあらためてやや詳しく調べる予定である。