DelFusa Blog 総本山

プログラミングの話題とかです。

NEW | PAGE-SELECT | NEXT

≫ EDIT

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

| スポンサー広告 | --:-- | comments(-) | trackbacks(-) | TOP↑

≫ EDIT

コンポーネントをインストールせずに使う方法

         _____
 ∧,,∧  /
ミ ,,゚Д゚,ミ<  コードどんどんかきまひょー
ミ    つ \ 
ミ∪  ミ      ̄ ̄ ̄ ̄ ̄ ̄
'∪'''∪'


-- コンポーネントをインストールせずに使う方法 --



コンポーネントのインストールは

わざわざIDEに登録しなければいけなかったり

インストールするパッケージを決めたりしなければならず少々面倒です。

複数のマシン環境で開発しているときなどは

特にそう感じるかもしれません。



そこで、コンポーネントをインストールなしに

使う方法を考えてみました。



設計時のRADに頼らずに

実行時(起動直後)にコンポーネントを生成すれば

問題なく使う事が出来るのですが

それでは各種プロパティの設定がかなり不便です。

せっかくのDelphiのRADパワーが台無し。



ですので、実行時生成を応用して

設計時には継承元コンポーネントとして振る舞い、

実行時には継承先コンポーネントに置き換わるというコードを書きます。



例えば TEdit を拡張して TMyEdit を作成する場合は

次のように継承しておくとよいでしょう。

────────────────────

type

 TMyEdit = class(TEdit)

 private

 protected

 public

  constructor CreateClone(Original: TEdit);

 published

 end;



constructor TMyEdit.CreateClone(Original: TEdit);

var

 MemStream: TMemoryStream;

begin

 Create(Original.Owner);

 Self.Parent := Original.Parent;



 MemStream := TMemoryStream.Create;

 try

  MemStream.WriteComponent(Original);

  Original.Free;

  MemStream.Position := 0;

  MemStream.ReadComponent(Self);



 finally

  MemStream.Free;

 end;

end;

────────────────────

CreateCloneコンストラクタで、

元の指定したコンポーネントのプロパティを

新しく生成したコンポーネントのプロパティに

移動させています。



あとは FormCreateイベントで

RADで配置した、TEditのEdit1を TMyEditのEdit1に

置き換えてしまいます。



procedure TForm1.FormCreate(Sender: TObject);

begin

 Edit1 := TMyEdit.CreateClone(Edit1);

end;



これで、TEditの全機能を継承した

TMyEditが使えるようになります。

上記サンプルでは

TMyEditでは、TEditと何の機能追加もない置き換えになっています。

あとは、自分で改造してください。



機能を付け加えた例として

CN_COMMAND メッセージによって OnSelEndCancel イベントを発生させる

TComboBox1クラスを作成しました。こちらも参考にしてください。

────────────────────

unit ComboBox1;



interface



uses

 Windows, Messages, SysUtils, Classes, Controls, StdCtrls;



type

 TComboBox1 = class(TComboBox)

 private

  FOnSelEndCancel: TNotifyEvent;

  procedure SelEndCancel;

 protected

  procedure CNCOMMAND(var Msg: TMessage); message CN_COMMAND;

 public

  constructor CreateClone(Original: TComboBox);

 published

  property OnSelEndCancel: TNotifyEvent read FOnSelEndCancel write FOnSelEndCancel;

 end;



implementation



constructor TComboBox1.CreateClone(Original: TComboBox);

var

 MemStream: TMemoryStream;

begin

 Create(Original.Owner);

 Self.Parent := Original.Parent;



 MemStream := TMemoryStream.Create;

 try

  MemStream.WriteComponent(Original);

  Original.Free;

  MemStream.Position := 0;

  MemStream.ReadComponent(Self);



 finally

  MemStream.Free;

 end;

end;



procedure TComboBox1.CNCOMMAND(var Msg: TMessage);

begin

 inherited;



 if Msg.WParamHi = CBN_SELENDCANCEL then

  SelEndCancel;

end;



procedure TComboBox1.SelEndCancel;

begin

 if Assigned(FOnSelEndCancel) then

  FOnSelEndCancel(Self);

end;



end.

────────────────────

Form側のコードは次のようになります。



procedure TForm1.FormCreate(Sender: TObject);

begin

 ComboBox1 := TComboBox1.CreateClone(ComboBox1);

 TComboBox1(ComboBox1).OnSelEndCancel := ComboBoxSelEndCancel;

end;



procedure TForm1.ComboBoxSelEndCancel(Sender: TObject);

begin

 Memo1.Lines.Add('SelendCancel');

end;



実質、ComboBox1のクラスをTComboBoxからTComboBox1へ置き換えて

いることになります。

TComboBoxから引き継いだプロパティはRADにて設定できますが

TComboBox1で新設したプロパティはRADで設定できないので

コンストラクタCreateClone後にコード上で設定してください。



作りっぱなしのコンポーネントや

開発中のコンポーネント、

単一プロジェクトでしか使わないコンポーネントを利用するときに

CreateClone のやり方は便利に使えるでしょう。



ネット上で見つけたコンポーネントを試したい場合などにも

パッケージにインストールするのは手間がかかるので

そのコンポーネントを改良したり継承したりして

CreateCloneを作り、

Formに貼り付けて動作確認すると、楽ですよ。

スポンサーサイト

| 未分類 | 02:26 | comments:7 | trackbacks:0 | TOP↑

COMMENT

ちょっと、TLaveledEditとか、変なのマヂっていたので、本文とソースをちょびっと修正しました。ヨロ。

| ⊂,,,,,,,,,つ,,゚Д゚ミつ | 2007/02/05 01:05 | URL |

はじめまして。
同僚に紹介されて拝見させて頂いております。

興味深いコードですね。
参考にさせていただいています。
ところでこのコード、Event 系のプロパティは引き継げないときがあるようですね。
CreateClone() に
Self.On~ = Original.On~
を書き連ねてますが、スマートな方法があったら是非ヒントでもいいので教えてください。

| とっさん | 2007/03/24 20:10 | URL |

あら、ほんとに~??

イベントハンドラ自体が
published
のプロパティ定義なら正しく動くと思うんだけど、、、

オブジェクトインスペクタで設定できる物は、全部、publishedだから、うまくいくはずなんだけどなあ。

無理だったらごめんね。

動作サンプルとかあったら、BBSで、聞いたらだれか答えてくれるかもだし。漏れのページの宣伝にもなって助かるな~~

DelphiQ&A掲示板は知ってるよね?

| ミ,,゚Д゚彡 | 2007/03/25 01:00 | URL |

レスありがとうございます。
そうなんですよね、published なものはすべてうまくいきそうですし、TMemoryStreamにもイベントハンドラを処理するそれらしきコードはあるのですが、何故か機能してくれないようです。
この件はDelphiQ&A掲示板で質問として上げさせていただきました。
これからも参考にさせていただきます。
では。

| とっさん | 2007/03/25 11:08 | URL |

DelphiQ&A掲示板で提示頂いたコードでうまくいきました。
整理したものを貼り付けます。

constructor TMyEdit.CreateClone(Original: TEdit);
var
BinStream: TStream;
Reader: TReader;
Writer: TWriter;
begin
inherited Create(Original.Owner);

BinStream := nil;
Reader := nil;
Writer := nil;
try
BinStream := TMemoryStream.Create;
try
Writer := TWriter.Create(BinStream, $1000);
Writer.Root := Original.Owner;
Writer.WriteSignature;
Writer.WriteComponent(Original);
Writer.WriteListEnd;
finally
FreeAndNil(Writer);
end;

try
Reader := TReader.Create(BinStream, $1000);
Reader.Root := Original.Owner;
Reader.Owner := Original.Owner;
Reader.Parent := Original.Parent;
Reader.Position := 0;

Original.Free;

Reader.BeginReferences;
Reader.ReadSignature;
Reader.ReadComponent(Self);
Reader.FixupReferences;
Reader.EndReferences;
finally
FreeAndNil(Reader);
end;

finally
FreeAndNil(BinStream);
end;
end;

| とっさん | 2007/03/26 22:18 | URL |

おみごと。

| ミ,,゚Д゚彡 | 2007/03/27 11:59 | URL |

コンストラクタを新設するのではなく、作り直すメソッドによるコードです。
説明はURLより

function ChangeComponent(old: TComponent; NewClass: TComponentClass): TComponent;
var
  new: TComponent;
  Stream: TStream;
  Methods: array of TMethod;
  aPPropInfo: array of PPropInfo;
  cnt, i: Integer;
begin
  SetLength(aPPropInfo, 16379);
  cnt := GetPropList(old.ClassInfo, [tkMethod],   @aPPropInfo[0]);
  SetLength(Methods, cnt);
  for i := 0 to cnt - 1 do Methods[i] := GetMethodProp(old, aPPropInfo[i]);
  Stream := TMemoryStream.Create;
  try
  Stream.WriteComponent(old);
  new := NewClass.Create(old.Owner);
  if new is TControl then TControl(new).Parent := TControl(old).Parent;
  Stream.Position := 0;
  old.Free;
  Stream.ReadComponent(new);
  finally Stream.free end;
  for i := 0 to cnt - 1 do SetMethodProp(new, aPPropInfo[i], Methods[i]);
  Result := new;
end;

| | 2007/05/11 21:44 | URL |















非公開コメント

TRACKBACK URL

http://delfusa.blog65.fc2.com/tb.php/40-1fe50855

TRACKBACK

PREV | PAGE-SELECT | NEXT

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。