TStringList.ObjectsのSave、Load

解決


T.Baba  2005-10-11 02:44:27  No: 18019

TStringlistのObjectsに関連付けられたコンポーネントのSave、Loadをしたいのですが、どのような方法が最適でしょうか?

ObjectsにはTComponentの継承クラスが必ず存在し、空になることはないためSaveToStreamをoverrideしてinherited SaveToStreamしたあと、TWriterを使い、WriteListBegin、WriteListEndでWriteComponentをはさみ、ひたすらコンポーネントをリストしようかと考えました。が、TWriterを扱ったことがないためTWriter.Create(Stream: TStream; BufSize: Integer);のBufSizeをいくつにしたらよいかがわからず、つまずきました。ヘルプを見てもこの値がいまいちわかりません。

また、他にうまくObjectsをSave、Loadする方法があれば教えていただきたいです。よろしくお願いします。[D6Per]


えーと  2005-10-11 03:21:03  No: 18020

Objects[] に記憶されているのはインスタンスのポインタに相当するものです。
これをセーブしても、次にロードしたとき、同じインスタンスが存在することは
一般にはないと思いますけど。


えーと  2005-10-11 03:23:26  No: 18021

BufSize については過去に議論がありました。

https://www.petitmonte.com/bbs/answers?question_id=2997


えーと  2005-10-11 03:27:35  No: 18022

> これをセーブしても、

あっ、勘違いでした。すみません。WriteComponent() ですね。


T.Baba  2005-10-11 05:55:59  No: 18023

レスありがとうございます。BufSizeについては検索で簡単にヒットしますね。お手数をおかけしましてすみませんでした。
TStringListを継承して次のようなクラスを作りました。

type
  TStrCompList = class(TStringList)
  private
    function GetComp(Index: Integer): TComponent;
    procedure PutComp(Index: Integer; const Value: TComponent);
  public
    procedure Clear; override;
    procedure SaveToStream(Stream: TStream); override;
    procedure LoadFromStream(Stream: TStream); override;
    property Objects[Index: Integer]: TComponent read GetComp write PutComp;
  end;

---
function TStrCompList.GetComp(Index: Integer): TComponent;
begin
  Result:= TComponent(inherited GetObject(Index));
end;

procedure TStrCompList.PutComp(Index: Integer; const Value: TComponent);
begin
  inherited PutObject(Index, Value);
end;

procedure TStrCompList.Clear;
var
  i: Integer;
begin
  for i:= 0 to Count-1 do Objects[i].Free;
  inherited;
end;

procedure TStrCompList.SaveToStream(Stream: TStream);
var
  i: Integer;
  w: TWriter;
begin
  w:= TWriter.Create(Stream, $fff);
  try
    w.WriteListBegin;
    for i:= 0 to Count-1 do begin
      w.WriteString(Strings[i]);
      w.WriteComponent(Objects[i]);
    end;
    w.WriteListEnd;
    w.FlushBuffer;
  finally
    w.Free;
  end;
end;

procedure TStrCompList.LoadFromStream(Stream: TStream);
var
  r: TReader;
begin
  Clear;
  r:= TReader.Create(Stream, $fff);
  try
    r.ReadListBegin;
    while not r.EndOfList do
      AddObject(r.ReadString, r.ReadComponent(nil));
    r.ReadListEnd;
    r.FlushBuffer;
  finally
    r.Free;
  end;
end;

ですが、AddObject('qwe',Button1)をしてSaveToStreamをするとw.WriteComponent(Objects[i]);でAccessViolationエラーが出てしまいます。
どこを直せばよいのでしょうか?よろしくお願いします。


@123  2005-10-11 07:25:24  No: 18024

Helpによると
WriteComponent メソッドを直接呼び出さないでください。
コンポーネントのプロパティが存在するかのテストが必要?
プロパティ関連のプログラムが不完全では。


えーと  2005-10-11 07:30:26  No: 18025

コンポーネントをストリーミングして何をなさりたいのか分かりませんが、

> w.WriteComponent(Objects[i]);

これだと Objects[] は TObject 型なので AV が起こるのでは?
明示的に w.WriteComponent(TButton(Objects[i])); とかでキャストするのかなぁ?

ヘルプによると

WriteComponent メソッドを直接呼び出さないでください。WriteComponent 
メソッドは Root プロパティ内の各所有コンポーネントで再帰的に呼び出されます。

となっていますので、IDE が使っているのでためしたことは無いです。


T.Baba  2005-10-12 04:18:43  No: 18026

@123さま、えーとさまレスありがとうございます。

>これだと Objects[] は TObject 型なので AV が起こるのでは?
>明示的に w.WriteComponent(TButton(Objects[i])); とかでキャストするのかなぁ?
Objects[]がTComponentを返すクラスにしてあるので。。。結局以下のようにしてうまくいったようです。何度もレスをしていただきありがとうございました。

procedure TStrCompList.SaveToStream(Stream: TStream);
var
  i: Integer;
  w: TWriter;
begin
  w:= TWriter.Create(Stream, $fff);
  try
    w.WriteListBegin;
    for i:= 0 to Count-1 do begin
      w.WriteString(Strings[i]);
      w.WriteRootComponent(Objects[i]);
    end;
    w.WriteListEnd;
  finally
    w.Free;
  end;
end;

procedure TStrCompList.LoadFromStream(Stream: TStream; AOwner: TComponent);
var
  i: Integer;
  r: TReader;
begin
  Clear;
  r:= TReader.Create(Stream, $fff);
  try
    r.ReadListBegin;
    while not r.EndOfList do
    begin
      i:= Add(r.ReadString);
      Objects[i]:= r.ReadRootComponent(nil);
      AOwner.InsertComponent(Objects[i]);
    end;
    r.ReadListEnd;
  finally
    r.Free;
  end;
end;


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

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






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