Sign in Join
Wiki copytemporary

Revision 1 of 2, by Aliotti on 9-19-2007. The page as it is now.

Streaming components/pt

Introdução

Normalmente, quando você necessita armazenar dados em disco ou rede, você deve escrever código para carregamento e o salvamento de cada propriedade. Este tutorial descreve como escrever classes, estas podem ter carregado de e conservado para os streams(fluxos) sem código extra da escrita ler/salvar usando o RTTI.

Aqui tem um exemplo nos fontes do lazarus, demonstrando como salvar um TGroupBox com um TCheckBox filho para uma stream(fluxo) e ler uma stream de volta para criar uma cópia de ambos os componentes.

 Veja <lazaruspath>/examples/componentstreaming/

Na combinação com RTTI controls você pode reduzir o tamanho de código necessário para conectar os dados do programa com a GUI e o Disco/Rede para um minímo.

TComponent / TPersistent

A classe TPersistent é definida na unidade Classes e estão utilizando a diretiva de compilação {$M+}. Esta diretiva diz ao compilado para criar o Tipo de Informação em Tempo de Execução (RTTI). Isto significa que e todos seus descendentes começam uma nova seção published da classe . Propriedades da 'Published'(difundida) são visíveis como a 'public'(pública), mas adicionalmente sua estrutura é acessível em tempo de execução. O que significa que toda propriedade difundida pode ser lida e escrita em tempo de execução. A IDE por exemplo usa este para trabalhar com componentes que nunca se ouviu.

TComponent extende a habilidade de TPersistent para ter componentes filhos. Isto é importante para streaming, onde um componente é o root component(raiz) também chamado de lookup root com uma lista de componentes filho.

TReader / TWriter

Aqui estão as classes que iremos trabalhar, que le/escreve um componente para/de um stream (Veja CreateLRSReader e CreateLRSWriter). Eles usam um Driver para ler/escrever um especial formato. No momento aqui temos um leitor (TLRSObjectReader) e um escritor (TLRSObjectWriter) de formato binário do objeto definido na unidade LResources e um escritor (TXMLObjectWriter) para TDOMDocument definido no Laz_XMLStreaming. A unidade LResources também contém funções para converter do formato binário par textual e vice-versa (LRSObjectBinaryToText, LRSObjectTextToBinary). A LCL prefere UTF8 para strings, enquanto o Delphi prefere Widestrings. Assim há algumas funções da conversão também.

Escrevendo seu próprio componente - Parte 1

Um componente próprio pode ser um simples como: type

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

Escrevendo um componente para uma stream

A unidade LResources tem a seguinte função:

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

Ela escreve um componente no formato binário num stream. Por exemplo:

pascal
procedure TForm1.Button1Click(Sender: TObject);
var
  AStream: TMemoryStream;
begin
  AStream:=TMemoryStream.Create;
  try
    WriteComponentAsBinaryToStream(AStream,AGroupBox);
    ... salvar a stream em algum lugar ...
  finally
    AStream.Free;
  end;
end;

Lendo um componente de um stream

A unidade LResources tem a seguinte função:

 procedure ReadComponentFromBinaryStream(AStream: TStream;
   var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);

Propriedades que podem ser guardadas num Stream

Há algumas limitações, que tipos TReader/TWriter podem colocar no stream:

Armazenadno Dados Customizados - DefineProperties

Você pode guardar arbitrariamente dados sobrescrevendo(overriding) DefineProperties. Isto habilita a guardar qualquer dado na stream, que não tem tipos básico. Por exemplo para armazenar uma variável FMyRect: TRect' de seu componente, adicione os seguintes três métodos:

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

Com o seguinte código:

pascal
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;
pascal
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;
pascal
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;

Este irá salvar MyRect como uma propriedade 'MyRec'.

Se você tem muitos objetos TRect, então você provavelmente não precisa escrever este código toda vez. A unidade LResources contém um exemplo de como escrever um procedimento para definir uma propriedade rect:

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

Desta maneira o código acima pode ser escrito de forma curta:

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

Escrevendo seu próprio componente - Parte 2

Agora o exemplo pode ser extendido e nós podemos usar propriedades arbitrárias com somente algumas linhas de código:

pascal
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;
pascal
procedure TMyComponent.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);
  DefineRectProperty(Filer,'Rect1',@FRect1,nil);
  DefineRectProperty(Filer,'Rect2',@FRect2,nil);
end;

Este componente pode agora ser salvo, lido ou usado pelos RTTI controls. Você não precisa escrever algum código a mais.


From the Free Pascal wiki, page "Streaming components/pt", as it stood on 2007-09-19 after a change by Aliotti, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.