Publish プロパティで、クラス(コンポーネント)を設定したい


maco  2007-04-26 19:56:54  No: 25942

次のようなコンポーネントを自作しました。
  TComp_Sub  … TFrameに複数のコンポーネントを貼り付けたコンポーネント
  TComp_Main … TFrameに複数のTComp_Subを貼り付けたコンポーネント

  ┏━━━━━━━┓
  ┃┌─────┐┃
  ┃│Comp_Sub1 │┃
  ┃└─────┘┃
  ┃┌─────┐┃
  ┃│Comp_Sub2 │┃
  ┃└─────┘┃
  ┃┌─────┐┃
  ┃│Comp_Sub3 │┃
  ┃└─────┘┃
  ┗━━━━━━━┛
  TComp_Mainのイメージ図

TComp_Main の Publish プロパティで、Comp_Sub1を直接指定したいと思っています。

property Comp_Sub1 : TComp_Sub read Comp_Sub1 write _SetCmpSub;

procedure _SetCmpSub(const Value : TComp_Sub);
begin
  Comp_Sub1.自作プロパティ := Value.自作プロパティ;
  //Comp_Sub1.Assign(Value);  // ←「TComp_Sub に TComp_Sub は代入できません」エラー
end;

上記のように「read Comp_Sub1」とすれば、
オブジェクトインスペクタでComp_Sub1の情報が見れるます。
しかし、
「write _SetCmpSub」でどのような処理をしても
オブジェクトインスペクタでの設定が反映されません。

フォーム > エディタで表示 で設定情報を確認しても
  Comp_Sub1 = Comp_Main.Comp_Sub1
と書かれているだけで、設定した情報は残っていません。

TComp_Main の プロパティに、TComp_Sub を直接指定し、
オブジェクトインスペクタでの設定情報を反映させることは出来ないのでしょうか?


みふ。  2007-04-27 20:43:54  No: 25943

これだけだと良く解らないけど?
CompSub1がSubComponentとしてエントリされてないから
DefineProperiesでスルーされてるとか?


maco  2007-05-07 23:53:15  No: 25944

> DefineProperiesでスルーされてるとか?

DefinePropertiesをoverrideすれば、
オブジェクトインスペクタで設定した Sub_Comp* の情報を保存できました。

>─── 宣言部 ──────
  private
    procedure ReadData(Reader: TReader);
    procedure WriteData(Writer: TWriter);

  protected
    procedure DefineProperties(Filer:TFiler); override;

>─── 実装部 ──────
  // DefinePropertiesのオーバライド
  procedure DefineProperties(Filer:TFiler);
  begin
    inherited;
    Filer.DefineProperties('Sub_Comp1_BooleanProperty', ReadData, GetData, True);
  end;

  // Sub_Comp1のプロパティの読み込み
  procedure ReadData(Reader: TReader);
  begin
    Sub_Comp1.Booleanプロパティ := Reader.ReadBoolean;
  end;
  
  // Sub_Comp1のプロパティの書き込み
  procedure WriteData(Writer: TWriter);
  begin
    Writer.WriteBoolean(Sub_Comp1.Booleanプロパティ);
  end;
  
>───────────────────────────

しかしこの方法だと、一つのプロパティに付き
  Sub_Comp*の個数分(8個) × Read&Writeで2つ = 16
16個のメソッドが必要となります。(*1)

そのため、以下のような集合型を宣言し
type
  TCompList = (Comp1,Comp2,Comp3,Comp4,Comp5,Comp6,Comp7,Comp8);
  TCompSet  = set of TCompList;
  
下記のように、publishに集合型のプロパティを宣言することにしました。
publish
  property Booleanプロパティ : TCompSet read FCompSet型変数 write FCompSet型変数に書き込むメソッド;
    Default [];

> CompSub1がSubComponentとしてエントリされてないから

「SubComponentとしてエントリされていない」とはどういう意味ですか?

(*1)
  1つのReadData、WriteDataメソッドを共有する方法があるのかも知れませんが、
  調べても良い事例がありませんでした。良い方法があれば、どなたか教えてください。


みふ。  2007-05-08 00:54:31  No: 25945

dfmに↓と出力されているのは?
>>Comp_Sub1 = Comp_Main.Comp_Sub1
CompSub1はCompMainが生成したCompSub1を参照する
まずこの時点で変な気がします?
参照型であるならForm上のComp_Sub1?と関連付けして
実際のComp_Sub1の情報はComp_Sub1として?
Formのコンテナ上に出力されますよね?

CompMainがComp_Sub1を生成して復元しなくてはいけないのであれば
n個ぶんの情報を出力可能な?
独自フォーマットを考えて、実行時型情報から取得するクラスを生成するとか?

それをしないで実現するなら?
TLabeledEditが持っているTBoundLabelを見てみてください
SetSubComponentが呼ばれているので
たぶんTLabeledEdit上でDefinePropertyもoverrideされてないと思います。
SetSubComponentは生成する側からでも大丈夫かもしれませんし
あなたが期待している結果では無いのかもしれませんが。。

後はコレクションを使って一度に出力するとか etc


maco  2007-05-09 01:32:38  No: 25946

> TLabeledEditが持っているTBoundLabelを見てみてください
> SetSubComponentが呼ばれている

みふ。さんありがとうございます。
期待通りのことが出来ました。

TComp_Mainクリエイトイベントで、
  TComp_Sub*.SetSubComponent(True);
と指定することで、オブジェクトインスペクタで指定したプロパティの保存が出来ました。

> dfmに↓と出力されているのは?
>>  Comp_Sub1 = Comp_Main.Comp_Sub1
> まずこの時点で変

上記のようにSetSubComponent(True)を指定することで、
  object Comp_Main : TComp_Main
    Sub_Comp1.プロパティ = 値
  end;
といった感じに、設定値を保存するようになりました。

> 後はコレクションを使って一度に出力する

コレクションを使うとはどのような方法ですか?


みふ。  2007-05-10 02:51:43  No: 25947

>コレクションを使うとはどのような方法ですか?

>しかしこの方法だと、一つのプロパティに付き
>Sub_Comp*の個数分(8個) × Read&Writeで2つ = 16
>16個のメソッドが必要となります。(*1)

'Sub_Comp'のDefineProperty内でSubComp*個分を
出力する事ができるのでRead/Weiteの二つですむだけです。。

DefinePropertiesはoverrideしなければいけませんし
CollectionItemを定義しないといけないので
SubComponent化で実現できているならその方が楽なはずです

SubCompの数をユーザーが決められる等のUIとなった場合等は
メリットがあるやも?

TReader/TWriterの
ReadListBegin/EndOfList/ReadCollection/ReadListEnd
あたりを使うと可能なはずです


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加