Streaming components/pt: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: Streaming components/pt
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## Introdução | |
| 2 | + | ||
| 3 | + | 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. | |
| 4 | + | ||
| 5 | + | 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. | |
| 6 | + | ||
| 7 | + | ` Veja <lazaruspath>/examples/componentstreaming/` | |
| 8 | + | ||
| 9 | + | 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. | |
| 10 | + | ||
| 11 | + | ## TComponent / TPersistent | |
| 12 | + | ||
| 13 | + | 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. | |
| 14 | + | ||
| 15 | + | **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. | |
| 16 | + | ||
| 17 | + | ## TReader / TWriter | |
| 18 | + | ||
| 19 | + | 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. | |
| 20 | + | ||
| 21 | + | ## Escrevendo seu próprio componente - Parte 1 | |
| 22 | + | ||
| 23 | + | Um componente próprio pode ser um simples como: type | |
| 24 | + | ||
| 25 | + | ` TMyComponent = class(TComponent)`\ | |
| 26 | + | ` private`\ | |
| 27 | + | ` FID: integer;`\ | |
| 28 | + | ` published`\ | |
| 29 | + | ` property ID: integer read FID write FID;`\ | |
| 30 | + | ` end;` | |
| 31 | + | ||
| 32 | + | ## Escrevendo um componente para uma stream | |
| 33 | + | ||
| 34 | + | A unidade [[doc:lcl/lresources|LResources]] tem a seguinte função: | |
| 35 | + | ||
| 36 | + | ` procedure WriteComponentAsBinaryToStream(AStream: TStream; AComponent: TComponent);` | |
| 37 | + | ||
| 38 | + | Ela escreve um componente no formato binário num stream. Por exemplo: | |
| 39 | + | ||
| 40 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 41 | + | var | |
| 42 | + | AStream: TMemoryStream; | |
| 43 | + | begin | |
| 44 | + | AStream:=TMemoryStream.Create; | |
| 45 | + | try | |
| 46 | + | WriteComponentAsBinaryToStream(AStream,AGroupBox); | |
| 47 | + | ... salvar a stream em algum lugar ... | |
| 48 | + | finally | |
| 49 | + | AStream.Free; | |
| 50 | + | end; | |
| 51 | + | end; | |
| 52 | + | ||
| 53 | + | ## Lendo um componente de um stream | |
| 54 | + | ||
| 55 | + | A unidade LResources tem a seguinte função: | |
| 56 | + | ||
| 57 | + | ` procedure ReadComponentFromBinaryStream(AStream: TStream;`\ | |
| 58 | + | ` var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);` | |
| 59 | + | ||
| 60 | + | - AStream é a stream contendo um componente no formato binário. | |
| 61 | + | - RootComponent é qualquer componente existente, cujo os dados serão sobre-escritos, ou esse é nil(valor vazio) um componente novo será criado. | |
| 62 | + | - OnFindComponentClass é uma função, que é usada pelo TReader para pegar a classe a partir de classnames na stream. Por exemplo: | |
| 63 | + | ||
| 64 | + | procedure TCompStreamDemoForm.OnFindClass(Reader: TReader; | |
| 65 | + | const AClassName: string; var ComponentClass: TComponentClass); | |
| 66 | + | begin | |
| 67 | + | if CompareText(AClassName,'TGroupBox')=0 then | |
| 68 | + | ComponentClass:=TGroupBox | |
| 69 | + | else if CompareText(AClassName,'TCheckBox')=0 then | |
| 70 | + | ComponentClass:=TCheckBox; | |
| 71 | + | end; | |
| 72 | + | ||
| 73 | + | - TheOwner é o componente raiz ou dono, quando criando um novo componente. | |
| 74 | + | ||
| 75 | + | ## Propriedades que podem ser guardadas num Stream | |
| 76 | + | ||
| 77 | + | Há algumas limitações, que tipos TReader/TWriter podem colocar no stream: | |
| 78 | + | ||
| 79 | + | - Tipos básicos podem ser armazenados na stream: string, integer, char, single, double, extended, byte, word, cardinal, shortint, method pointers, etc. . | |
| 80 | + | - TPersistent e seus descendentes podem ser armazenados na stream | |
| 81 | + | - records, objects e classes não descendendo de TPersistent não podem ser guardadas. Para armazená-los você precisa dizer como no TReader/TWriter. Veja a seguir em armazenando dados customizados - DefineProperties. | |
| 82 | + | ||
| 83 | + | ## Armazenadno Dados Customizados - DefineProperties | |
| 84 | + | ||
| 85 | + | 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: | |
| 86 | + | ||
| 87 | + | procedure DefineProperties(Filer: TFiler); override; | |
| 88 | + | procedure ReadMyRect(Reader: TReader); | |
| 89 | + | procedure WriteMyRect(Writer: TWriter); | |
| 90 | + | ||
| 91 | + | Com o seguinte código: | |
| 92 | + | ||
| 93 | + | procedure TMyComponent.DefineProperties(Filer: TFiler); | |
| 94 | + | var | |
| 95 | + | MyRectMustBeSaved: Boolean; | |
| 96 | + | begin | |
| 97 | + | inherited DefineProperties(Filer); | |
| 98 | + | MyRectMustBeSaved:=(MyRect.Left<>0) | |
| 99 | + | or (MyRect.Top<>0) | |
| 100 | + | or (MyRect.Right<>0) | |
| 101 | + | or (MyRect.Bottom<>0); | |
| 102 | + | Filer.DefineProperty('MyRect',@ReadMyRect,@WriteMyRect,MyRectMustBeSaved); | |
| 103 | + | end; | |
| 104 | + | ||
| 105 | + | procedure TMyComponent.ReadMyRect(Reader: TReader); | |
| 106 | + | begin | |
| 107 | + | with Reader do begin | |
| 108 | + | ReadListBegin; | |
| 109 | + | FMyRect.Left:=ReadInteger; | |
| 110 | + | FMyRect.Top:=ReadInteger; | |
| 111 | + | FMyRect.Right:=ReadInteger; | |
| 112 | + | FMyRect.Bottom:=ReadInteger; | |
| 113 | + | ReadListEnd; | |
| 114 | + | end; | |
| 115 | + | end; | |
| 116 | + | ||
| 117 | + | procedure TMyComponent.WriteMyRect(Writer: TWriter); | |
| 118 | + | begin | |
| 119 | + | with Writer do begin | |
| 120 | + | WriteListBegin; | |
| 121 | + | WriteInteger(FMyRect.Left); | |
| 122 | + | WriteInteger(FMyRect.Top); | |
| 123 | + | WriteInteger(FMyRect.Right); | |
| 124 | + | WriteInteger(FMyRect.Bottom); | |
| 125 | + | WriteListEnd; | |
| 126 | + | end; | |
| 127 | + | end; | |
| 128 | + | ||
| 129 | + | Este irá salvar MyRect como uma propriedade 'MyRec'. | |
| 130 | + | ||
| 131 | + | 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: | |
| 132 | + | ||
| 133 | + | ` procedure DefineRectProperty(Filer: TFiler; const Name: string; ARect, DefaultRect: PRect);`\ | |
| 134 | + | ||
| 135 | + | Desta maneira o código acima pode ser escrito de forma curta: | |
| 136 | + | ||
| 137 | + | procedure TMyComponent.DefineProperties(Filer: TFiler); | |
| 138 | + | begin | |
| 139 | + | inherited DefineProperties(Filer); | |
| 140 | + | DefineRectProperty(Filer,'MyRect',@FMyRect,nil); | |
| 141 | + | end; | |
| 142 | + | ||
| 143 | + | ## Escrevendo seu próprio componente - Parte 2 | |
| 144 | + | ||
| 145 | + | Agora o exemplo pode ser extendido e nós podemos usar propriedades arbitrárias com somente algumas linhas de código: | |
| 146 | + | ||
| 147 | + | type | |
| 148 | + | TMyComponent = class(TComponent) | |
| 149 | + | private | |
| 150 | + | FID: integer; | |
| 151 | + | FRect1: TRect; | |
| 152 | + | FRect2: TRect; | |
| 153 | + | protected | |
| 154 | + | procedure DefineProperties(Filer: TFiler); override; | |
| 155 | + | public | |
| 156 | + | property Rect1: TRect read FRect1 write FRect1; | |
| 157 | + | property Rect2: TRect read FRect2 write FRect2; | |
| 158 | + | published | |
| 159 | + | property ID: integer read FID write FID; | |
| 160 | + | end; | |
| 161 | + | ||
| 162 | + | procedure TMyComponent.DefineProperties(Filer: TFiler); | |
| 163 | + | begin | |
| 164 | + | inherited DefineProperties(Filer); | |
| 165 | + | DefineRectProperty(Filer,'Rect1',@FRect1,nil); | |
| 166 | + | DefineRectProperty(Filer,'Rect2',@FRect2,nil); | |
| 167 | + | end; | |
| 168 | + | ||
| 169 | + | Este componente pode agora ser salvo, lido ou usado pelos [[RTTI controls]]. Você não precisa escrever algum código a mais. | |
| 170 | + | ||
| 171 | + | --- | |
| 172 | + | *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](/wiki-contact).* |
