Difference between revisions of "Streaming components/ja"

From Lazarus wiki
Jump to navigationJump to search
Line 6: Line 6:
 
通常、ハードディスクやネットワークストリームにデータを蓄えておく場合は、それらの特性に応じてロードやセーブ(読み込みや書き込み)のためのコードを書かなければなりません。このチュートリアルでは、余分な load/save コードを書くことなく、RTTI を使用して、ストリームから読み込みや書き込みを行うクラスの書き方について述べます。
 
通常、ハードディスクやネットワークストリームにデータを蓄えておく場合は、それらの特性に応じてロードやセーブ(読み込みや書き込み)のためのコードを書かなければなりません。このチュートリアルでは、余分な load/save コードを書くことなく、RTTI を使用して、ストリームから読み込みや書き込みを行うクラスの書き方について述べます。
  
There is an example in the lazarus sources, demonstrating how to save a TGroupBox with a TCheckBox child to a stream and read the stream back to create a copy of both components.
+
lazarus コードでのサンプルや TCheckBox を含んだ TGroupBox をストリームに保存したり、両方のコンポーネントのコピーを作成してストリームから戻すといったデモを説明します。
  
 
   <lazaruspath>/examples/componentstreaming/ を参照してください。
 
   <lazaruspath>/examples/componentstreaming/ を参照してください。
  
 
RTTI コントロールとのコンビネーションで、GUI と ディスク/ネットワークとの間でプログラムデータをやり取りする際に必要なコードの量を最小限にすることができます。
 
RTTI コントロールとのコンビネーションで、GUI と ディスク/ネットワークとの間でプログラムデータをやり取りする際に必要なコードの量を最小限にすることができます。
 
  
 
== TComponent / TPersistent ==
 
== TComponent / TPersistent ==

Revision as of 05:16, 22 August 2006

Deutsch (de) English (en) français (fr) 日本語 (ja) polski (pl) português (pt)

日本語版メニュー
メインページ - Lazarus Documentation日本語版 - 翻訳ノート - 日本語障害情報

はじめに

通常、ハードディスクやネットワークストリームにデータを蓄えておく場合は、それらの特性に応じてロードやセーブ(読み込みや書き込み)のためのコードを書かなければなりません。このチュートリアルでは、余分な load/save コードを書くことなく、RTTI を使用して、ストリームから読み込みや書き込みを行うクラスの書き方について述べます。

lazarus コードでのサンプルや TCheckBox を含んだ TGroupBox をストリームに保存したり、両方のコンポーネントのコピーを作成してストリームから戻すといったデモを説明します。

 <lazaruspath>/examples/componentstreaming/ を参照してください。

RTTI コントロールとのコンビネーションで、GUI と ディスク/ネットワークとの間でプログラムデータをやり取りする際に必要なコードの量を最小限にすることができます。

TComponent / TPersistent

TPersistent クラスは、Classes ユニット内で定義され、{$M+}というコンパイラスイッチで使用されます。このスイッチは Run Time Type Information(RTTI)を作成することをコンパイラに伝えます。このことは、それもしくはそれらの派生が新しいクラスセクションを作成することを意味します。'Published' のプロパティは'public'のプロパティように使用することができますが、加えてこの構造体がランタイムからアクセス可能になります。これは全ての Published のプロパティがランタイムから読み書きできることを意味します。IDE の例でいえば、一度も聞いたことのない(使用したことがない)コンポーネントを動かす際に使用します。

TComponent extends TPersistent by the ability to have child components. This is important for streaming, where one component is the root component also called lookup root with a list of child components.

TReader / TWriter

These are the worker classes, which reads/writes a TComponent to/from a stream (See CreateLRSReader and CreateLRSWriter). They use a Driver to read/write a special format. At the moment there are a reader (TLRSObjectReader) and a writer (TLRSObjectWriter) for binary object format defined in the LResources unit and a writer (TXMLObjectWriter) for TDOMDocument defined in Laz_XMLStreaming. The LResources unit also contains functions to convert binary format to text and back (LRSObjectBinaryToText, LRSObjectTextToBinary). The LCL prefers UTF8 for strings, while Delphi prefers Widestrings. So there are some conversion functions as well.

独自コンポーネントの書き方 - Part 1

カスタムコンポーネントは次のようにシンプルです:

type
 TMyComponent = class(TComponent)
 private
   FID: integer;
 published
   property ID: integer read FID write FID;
 end;

Writing a component to a stream

LResources ユニットには次のような関数があります:

 procedure WriteComponentAsBinaryToStream(AStream: TStream; AComponent: TComponent);

It writes a component in binary format to the stream. For example:

procedure TForm1.Button1Click(Sender: TObject);
var
  AStream: TMemoryStream;
begin
  AStream:=TMemoryStream.Create;
  try
    WriteComponentAsBinaryToStream(AStream,AGroupBox);
    ... save stream somewhere ...
  finally
    AStream.Free;
  end;
end;

Reading a component from a stream

LResources には次のような関数があります:

 procedure ReadComponentFromBinaryStream(AStream: TStream;
   var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);
  • AStream is the stream containing a component in binary format.
  • RootComponent is either an existing component, which data will be overwritten, or it is nil and a new component will be created.
  • OnFindComponentClass is a function, that is used by TReader to get the class from the classnames in the stream. For example:
procedure TCompStreamDemoForm.OnFindClass(Reader: TReader;
  const AClassName: string; var ComponentClass: TComponentClass);
begin
  if CompareText(AClassName,'TGroupBox')=0 then
    ComponentClass:=TGroupBox
  else if CompareText(AClassName,'TCheckBox')=0 then
    ComponentClass:=TCheckBox;
end;
  • コンポーネントを新規に生成した場合、OWner にはそのコンポーネントのオーナーとなります。

Streamable properties

There are some limitations, what types TReader/TWriter can stream:

  • Base types can be streamed: string, integer, char, single, double, extended, byte, word, cardinal, shortint, method pointers, etc. .
  • TPersistent and descendants can be streamed

Streaming custom Data - DefineProperties

You can stream additinal arbitrary data by overriding DefineProperties. This allows to stream all data, that have no base types. For example to stream a variable FMyRect: TRect of your component, add the following three methods to your component:

procedure DefineProperties(Filer: TFiler); override;
procedure ReadMyRect(Reader: TReader);
procedure WriteMyRect(Writer: TWriter);

続けて次のコードを記述します:

procedure TMyComponent.DefineProperties(Filer: TFiler);
var
  MyRectMustBeSaved: Boolean;
begin
  inherited DefineProperties(Filer);
  MyRectMustBeSaved:=(MyRect.Left<>0)
                     or (MyRect.Top<>0)
                     or (MyRect.Right<>0)
                     or (MyRect.Bottom<>0);
  Filer.DefineProperty('MyRect',@ReadMyRect,@WriteMyRect,MyRectMustBeSaved);
end;

procedure TMyComponent.ReadMyRect(Reader: TReader);
begin
  with Reader do begin
    ReadListBegin;
    FMyRect.Left:=ReadInteger;
    FMyRect.Top:=ReadInteger;
    FMyRect.Right:=ReadInteger;
    FMyRect.Bottom:=ReadInteger;
    ReadListEnd;
  end;
end;

procedure TMyComponent.WriteMyRect(Writer: TWriter);
begin
  with Writer do begin
    WriteListBegin;
    WriteInteger(FMyRect.Left);
    WriteInteger(FMyRect.Top);
    WriteInteger(FMyRect.Right);
    WriteInteger(FMyRect.Bottom);
    WriteListEnd;
  end;
end;

This will save MyRect as a property 'MyRect'.

If you stream a lot of TRect, then you probably do not want to write everytime ths code. The unit LResources contains an example how to write a procedure to define a rect property:

 procedure DefineRectProperty(Filer: TFiler; const Name: string; ARect, DefaultRect: PRect);
 

上述の方法はこのように非常に短く記述することもできます:

procedure TMyComponent.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);
  DefineRectProperty(Filer,'MyRect',@FMyRect,nil);
end;

独自コンポーネント - Part 2

Now the example can be extended and we can use arbitrary properties with only a few lines of code:

type
  TMyComponent = class(TComponent)
  private
    FID: integer;
    FRect1: TRect;
    FRect2: TRect;
  protected
    procedure DefineProperties(Filer: TFiler); override;
  public
    property Rect1: TRect read FRect1 write FRect1;
    property Rect2: TRect read FRect2 write FRect2;
  published
    property ID: integer read FID write FID;
  end;

procedure TMyComponent.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);
  DefineRectProperty(Filer,'Rect1',@FRect1,nil);
  DefineRectProperty(Filer,'Rect2',@FRect2,nil);
end;

このコンポーネントは RTTI コントロール を使用して、保存、読み込み利用ができます。これ以上、詳細なコードを書く必要はありません。

Writing and Reading components from/to XML

Streaming components is simple: See the example in lazarus/examples/xmlstreaming/.

Conclusion

RTTI is a powerful mechanism, which can be used to easily stream whole classes and helps avoiding writing a lot of boring load/save code.

こちらも参照してください。

RTTI controls