2

多数のイベントハンドラーを含むデザインおよびランタイムコンポーネントがあります。今はTNewCompと呼びます。TFormでTNewCompのインスタンスを作成し、設計時にプロパティエディターを使用してイベントスタブに特定のコードを入力し、現在のイベントハンドラーコードのセットを使用するTNewcompの新しいインスタンスを作成できるようにしたいと考えています。

これを行うには、TNewCompのコンストラクターを呼び出してから、新しいインスタンスの各イベントハンドラーに、設計時に作成されたTNewCompインスタンスを含むフォームに常駐する対応するイベントスタブコードを「手動で」割り当てます。したがって、TNewFormというフォームのFNewCompという名前の変数にTNewCompのインスタンスが割り当てられている場合、イベントハンドラーごとに次のようにします。

FNewComp.onSomething = TNewform.onSomething
(... repeat for each event handler belonging to TNewComp ...)

これは問題なく機能しますが、面倒でさらに悪いことに、TNewCompに新しいイベントハンドラーを追加する場合は、「newTComp()」関数を更新してイベントハンドラーを割り当てることを忘れないでください。動的に新しいインスタンスを作成するすべての一意のコンポーネントタイプについて、このプロセスをすすぎ、繰り返します。

おそらくプロパティ検査または他のDelphi6イントロスペクション手法を使用して、このプロセスを自動化する方法はありますか?

-ロシュラー

4

3 に答える 3

4

次のコードを使用しました。作成するときは、宛先の所有者に注意してください。最も安全な方法は、Nilを渡し、後で自分でコンポーネントを解放することです。

implementation uses typinfo;

procedure CopyComponent(Source, Dest: TComponent);
var
  Stream: TMemoryStream;
  TypeData : PTypeData;
  PropList: PPropList;
  i, APropCount: integer;
begin
  Stream:=TMemoryStream.Create;
  try
    Stream.WriteComponent(Source);
    Stream.Position:=0;
    Stream.ReadComponent(Dest);
  finally
    Stream.Free;
  end;

  TypeData := GetTypeData(Source.ClassInfo);
  if (TypeData <> nil) then
  begin
    GetMem(PropList, SizeOf(PPropInfo)*TypeData^.PropCount);
    try
      APropCount:=GetPropList(Source.ClassInfo, [tkMethod], PropList);
      for i:=0 to APropCount-1 do
        SetMethodProp(Dest, PropList[i], GetMethodProp(Source, PropList[i]))
    finally
      FreeMem(PropList);
    end;
  end;
end;
于 2011-07-06T19:40:55.063 に答える
2

1つのオプションは、「適切に設定されたコンポーネント」をストリームに保存し、そのストリームを、Delphi IDE /ランタイムによって実行されるかのように、動的に作成された新しいコンポーネントにロードすることです。

もう1つのオプションは、TypInfoユニットであるRTTIを使用することです。そこには、利用可能なイベント(TypeKind )GetPropListを照会できる関数witchがあり、イベントハンドラーを使用して1つのコンポーネントから別のコンポーネントにコピーできます。tkMethodGetMethodPropSetMethodProp

于 2011-07-06T18:45:20.973 に答える
1

Makseeのソリューションを次のように微調整しました。

function CopyComponent(Source: TComponent; Owner: TComponent = nil): TComponent;
var
    Stream: TMemoryStream;
    TypeData : PTypeData;
    PropList: PPropList;
    i, APropCount: integer;
begin
    if not Assigned(Source) then
        raise Exception.Create('(CopyComponent) The Source component is not assigned.');

    Result := TComponent.Create(Owner);

    Stream := TMemoryStream.Create;

    try
        Stream.WriteComponent(Source);
        Stream.Position := 0;
        Stream.ReadComponent(Result);
    finally
        Stream.Free;
    end; // try()

    // Get the type data for the Source component.
    TypeData := GetTypeData(Source.ClassInfo);

    if (TypeData <> nil) then
    begin
        // Get the property information for the source component.
        GetMem(PropList, SizeOf(PPropInfo) * TypeData^.PropCount);

        try
            // Get the properties count.
            APropCount := GetPropList(Source.ClassInfo, [tkMethod], PropList);

            // Assign the source property methods to the destination.
            for i := 0 to APropCount - 1 do
                SetMethodProp(Result, PropList[i], GetMethodProp(Source, PropList[i]))

        finally
            // Free the property information object.
            FreeMem(PropList);
        end; // try()
    end; // if (TypeData <> nil) then
end;

そのため、既存のコンポーネント参照(MakseeのバージョンのDestパラメーター)を渡すのではなく、関数によって新しいコンポーネントが返されます。この亜種に起因する欠陥や問題が誰かに見られる場合は、コメントしてください。

于 2011-10-15T18:57:43.957 に答える