Cópia da wikiespelho

Este é um espelho da wiki em pascal.chat. A edição, o histórico e a entrada ficam lá.

Streaming components/pt

Deutsch · English · Français · Polski · Português · 日本語

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.

text
 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

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

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

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

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

Revisão 2, última alteração por WikiArchive .