コンポーネントをインストールせずに使う方法
24 ChangeComponent 動作確認 Delphi2007 更新日 2008/01/21(月)
2008/03/26(木)

Delphiでは開発環境(IDE)に
コンポーネントをインストールできます。

BDS2006付属のDelphi2006互換である
TurboDelphi Explorer 無料版では
この機能は制限されています。

複数のプロジェクトで使うような
汎用コンポーネントならインストールの手間は気になりませんが
一度のプロジェクトだけしか使わない改造コンポーネントを
IDEにインストールする気は失せてしまいます。

その場合、そのプロジェクトにコンポーネントを含んで
ソースコード内で動的生成してしまいましょう。

非常に簡単ですし、このコードを利用すれば
わずか1行を新たに記述することでコンポーネントを使えます。

もちろん、TurboDelphi Explorer 無料版でも使えて
無料版の制限を全く気にならなくさせるテクニックです。



まず、その改造コンポーネントが標準VCLの何のクラスから
派生しているかをしっておいてください。

例えばButtonEx.pasにTButtonExという
TButton派生のクラスを作っているとします。

ButtonEx.pasをプロジェクトと同じフォルダに配置して
Form上にTButtonのButton1を配置します。

次のようにコードを書いてください。
────────────────────
uses
  ButtonEx,
  TypInfo;

//コンポーネントを交換する関数
//usesにTypInfoを追加必要
function ChangeComponent(Original: TComponent; NewClass: TComponentClass): TComponent;
var
  New: TComponent;
  Stream: TStream;
  Methods: array of TMethod;
  aPPropInfo: array of PPropInfo;
  MethodCount, i: Integer;
begin
  SetLength(aPPropInfo, 16379);
  MethodCount := GetPropList(Original.ClassInfo, [tkMethod], @aPPropInfo[0]);
  SetLength(Methods, MethodCount);
  for i := 0 to MethodCount - 1 do
    Methods[i] := GetMethodProp(Original, aPPropInfo[i]);

  Stream := TMemoryStream.Create; try
  Stream.WriteComponent(Original);
  New := NewClass.Create(Original.Owner);
  if New is TControl then
    TControl(New).Parent := TControl(Original).Parent;
  Original.Free;
  Stream.Position := 0;
  Stream.ReadComponent(New);
  finally Stream.free end;

  for i := 0 to MethodCount - 1 do
    SetMethodProp(New, aPPropInfo[i], Methods[i]);
  Result := New;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1 := TButton(ChangeComponent(Button1, TButtonEx));
end;
────────────────────
これで、ButtonはTButtonExのクラスとして動作します。

TButtonEx独自の機能、例えばプロパティなどに値を代入する場合は
  TButtonEx(Button1).MyProperty := 値
と型キャストを行って実行することができます。

このChangeComponentは
Publishedプロパティ、
つまりオブジェクトインスペクタで設定できるプロパティを
他のコンポーネントに引き継ぐ事ができる
仕組みになっています。

イベントも引き継げます。



例えば、拡張ボタンとして有名なものを試しに実行してみましょう。

パンタグラフ(fumika)さんの
COSMIC TOWER TCuteButton
http://homepage1.nifty.com/cosmic/delphi/vcl.html

Mr.XRAYさんの
均等割付グラデーションボタン
http://homepage2.nifty.com/Mr_XRAY/Delphi/plButton/index.htm

これらのコンポーネントはButtonなのに
TCustomPanelから派生しています。

そこで、TCustomPanelからの直接の派生ではないですが
ほぼ同一であるTPanelをFormに貼り付けて、



次のコードを書いておきます。
────────────────────
uses
  plButton,
  CuteBtn,
  TypInfo;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Panel1 := TPanel(ChangeComponent(Panel1, TCuteButton));
  TCuteButton(Panel1).Color := clLime;

  Panel2.Caption := '';
  Panel2 := TPanel(ChangeComponent(Panel2, TplButton));
  TplButton(Panel2).Gradation := True;
  TplButton(Panel2).CaptionA.Caption := 'テスト';
  TplButton(Panel2).CaptionB.Caption := 'テスト';
end;
────────────────────
ChangeComponentを記述して
各ボタンの独自プロパティをコード上で設定しています。

実行した結果です。



Captionに空文字を代入しているのは
TCustomPanelにはCaptionプロパティがpublishedで公開されていない為
ChangeComponentの仕組みで引き継ぐ時に
TplButtonにはCaptionが無い!というエラーが出るため、
空文字を代入してプロパティを引き継がないようにしています。


追記:
毎回、TCuteButton(Panel1)やTplButton(Panel2)と
キャスト指定するのはかっこよくありませんね。

Panel1とPanel2はデザイン時にだけ使って
後はCuteButtonとplButtonは
自分で変数宣言して代入して使いましょう。
────────────────────
uses
  plButton,
  CuteBtn,
  TypInfo;
  
type
  TForm11 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Panel1Click(Sender: TObject);
    procedure Panel2Click(Sender: TObject);
  private
  public
    plButton1: TplButton;
    CuteButton1: TCuteButton;
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CuteButton1 := TCuteButton(ChangeComponent(Panel1, TCuteButton));
  CuteButton1.Color := clLime;

  Panel2.Caption := '';
  plButton1 := TplButton(ChangeComponent(Panel2, TplButton));
  plButton1.Gradation := True;
  plButton1.CaptionA.Caption := 'テスト';
  plButton1.CaptionB.Caption := 'テスト';
end;

procedure TForm11.Panel1Click(Sender: TObject);
begin
  ShowMessage('CuteButtonテスト');
end;

procedure TForm11.Panel2Click(Sender: TObject);
begin
  ShowMessage('plButtonテスト');
end;
────────────────────
これでより便利です。


参考────────────────────
DelFusaBlog コンポーネントをインストールせずに使う方法
http://delfusa.blog65.fc2.com/blog-entry-40.html

DelWiki - コード倉庫/コンポの付け替え
http://delwiki.info/?コード倉庫/コンポの付け替え