Difference between revisions of "Streaming components/fr"
Paulatreides (talk | contribs) |
Paulatreides (talk | contribs) |
||
Line 24: | Line 24: | ||
L'unité LResources contient également des fonctions pour convertir le format binaire en texte et l'inverse (LRSObjectBinaryToText, LRSObjectTextToBinary). La bibliothèque LCL préfère le codage UTF8 pour les chaînes de caractères, tandis que Delphi préfère Widestrings . Donc il y a également quelques fonctions de conversion. | L'unité LResources contient également des fonctions pour convertir le format binaire en texte et l'inverse (LRSObjectBinaryToText, LRSObjectTextToBinary). La bibliothèque LCL préfère le codage UTF8 pour les chaînes de caractères, tandis que Delphi préfère Widestrings . Donc il y a également quelques fonctions de conversion. | ||
− | == | + | == Ecriture de votre propre composant - Partie 1 == |
− | + | Un composant habituel peut être aussi simple que : | |
type | type | ||
TMyComponent = class(TComponent) | TMyComponent = class(TComponent) |
Revision as of 19:13, 28 June 2007
│
Deutsch (de) │
English (en) │
français (fr) │
日本語 (ja) │
polski (pl) │
português (pt) │
Introduction
Normalement, quand vous voulez stocker des données sur le disque ou par le réseau, vous devez écrire le code pour le chargement et la sauvegarde de chaque propriété. Ce tutoriel décrit comment écrire des classes , cela peut être chargé et sauvé à partir de flux sans charge supplémentaire de code de chargement/sauvegarde en utilisant la RTTI.
Il y a un exemple dans les sources lazarus, démontrant comment enregistrer un TGroupBox avec un enfant TCheckBox vers un flux et lire le flux de nouveau pour créer une copie des deux composants .
Voir <lazaruspath>/examples/componentstreaming/
En combination avec Les contrôles RTTI vous pouvez réduire la quantité de code nécessaire pour connecter les données du programme avec le GUI et le Disque/Réseau à un minimum .
TComponent / TPersistent
La classe TPersistent est définie dans l'unité Classes et utilise la directive du compilateur {$M+} . Cette directive dit au compilateur de créer de l'information pendant le temps d'exécution (RTTI). Ceci signifie que lui et tous ses descendants obtiennent une nouvelle section de classe published. les propriétés 'published' sont visibles comme 'public', mais additionnellement leur structure est accessible pendant le temps d'exécution . Cela signifie que toutes propriétés published peut être lu et écrite pendant le temps d'execution. L'IDE par exemple emploie ceci pour travailler avec des composants dont il n'a jamais entendus parler .
TComponent prolonge 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
Ce sont les classes qui travaillent, qui lisent/écrivent un TComponent vers/depuis un flux (Voir CreateLRSReader et CreateLRSWriter). Elles emploient un Pilote pour lire /écrire un format spécial . En ce moment, il y a un lecteur(TLRSObjectReader), un writer (TLRSObjectWriter) pour le format d'objet binaire défini dans l'unité LResources et un writer (TXMLObjectWriter) pour TDOMDocument défini dans Laz_XMLStreaming. L'unité LResources contient également des fonctions pour convertir le format binaire en texte et l'inverse (LRSObjectBinaryToText, LRSObjectTextToBinary). La bibliothèque LCL préfère le codage UTF8 pour les chaînes de caractères, tandis que Delphi préfère Widestrings . Donc il y a également quelques fonctions de conversion.
Ecriture de votre propre composant - Partie 1
Un composant habituel peut être aussi simple que : type
TMyComponent = class(TComponent) private FID: integer; published property ID: integer read FID write FID; end;
Writing a component to a stream
The unit LResources has a function for that:
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
The unit LResources has a function for that:
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;
- TheOwner is the component owner, when creating a new component.
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
- records, objects and classes not descending from TPersistent can not be streamed. To stream them you need to tell TReader/TWriter how. See below #Streaming custom Data - DefineProperties.
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);
With the following code:
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);
This way the above code can be written this short:
procedure TMyComponent.DefineProperties(Filer: TFiler); begin inherited DefineProperties(Filer); DefineRectProperty(Filer,'MyRect',@FMyRect,nil); end;
Writing your own component - 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;
This component can now be saved, loaded or used by the Les contrôles RTTI. You don't need to write any further code.
Writing and Reading components from/to XML
Streaming components is simple: See the example in lazarus/examples/xmlstreaming/.
Conclusion
RTTI est un mécanisme puissant, which can be used to easily stream whole classes and helps avoiding writing a lot of boring load/save code.
Voir également