Difference between revisions of "Streaming components/fr"
Line 12: | Line 12: | ||
== TComponent / TPersistent == | == TComponent / TPersistent == | ||
− | La classe '''TPersistent''' est définie dans l'unité Classes et utilise la directive | + | La classe '''TPersistent''' est définie dans l'unité '''Classes''' et utilise la directive de compilation '''{$M+}''' . Cette directive dit au compilateur de créer de l'information pendant le temps d'exécution ('''RTTI'''). Lui et tous ses descendants comprennent alors une nouvelle section de classe '''published'''. Les propriétés '''published''' sont visibles comme si elles étaient '''public''', mais leur structure est aussi accessible pendant le temps d'exécution. Cela signifie que toute propriété '''published''' peut être lue et écrite pendant ce temps d'exécution. Par exemple, l'EDI emploie cette technique pour travailler avec des composants dont il n'a jamais entendu parler. |
− | '''TComponent''' étend les possibilités de '''TPersistent''' par sa capacité à posséder des composants enfants. Cette capacité est importante pour le traitement des flux : un composant est le composant racine (appelé parfois '''lookup root''') | + | '''TComponent''' étend les possibilités de '''TPersistent''' par sa capacité à posséder des composants enfants. Cette capacité est importante pour le traitement des flux : un composant est le composant racine (appelé parfois '''lookup root''') qui gère une liste de composants enfants. |
== TReader / TWriter == | == TReader / TWriter == |
Revision as of 13:51, 19 April 2015
│
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 le réseau, vous devez écrire le code pour le chargement et l'enregistrement de chaque propriété. Ce tutoriel décrit comment écrire des classes qui peuvent être chargées et enregistrées à partir de flux sans charge supplémentaire de code de chargement/enregistrement, tout cela en utilisant la RTTI.
Vous trouverez un exemple dans les sources de Lazarus démontrant comment enregistrer un TGroupBox avec un enfant TCheckBox vers un flux et relire ce flux pour créer une copie des deux composants. Voir <lazaruspath>/examples/componentstreaming/
En combinaison avec Les contrôles RTTI, vous pouvez réduire au minimum la quantité de code nécessaire pour connecter les données du programme avec le GUI et le Disque/Réseau.
TComponent / TPersistent
La classe TPersistent est définie dans l'unité Classes et utilise la directive de compilation {$M+} . Cette directive dit au compilateur de créer de l'information pendant le temps d'exécution (RTTI). Lui et tous ses descendants comprennent alors une nouvelle section de classe published. Les propriétés published sont visibles comme si elles étaient public, mais leur structure est aussi accessible pendant le temps d'exécution. Cela signifie que toute propriété published peut être lue et écrite pendant ce temps d'exécution. Par exemple, l'EDI emploie cette technique pour travailler avec des composants dont il n'a jamais entendu parler.
TComponent étend les possibilités de TPersistent par sa capacité à posséder des composants enfants. Cette capacité est importante pour le traitement des flux : un composant est le composant racine (appelé parfois lookup root) qui gère une liste de composants enfants.
TReader / TWriter
Ce sont les classes 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;
Ecrire un composant sur un flux
L'unité LResources a une fonction pour cela :
procedure WriteComponentAsBinaryToStream(AStream: TStream; AComponent: TComponent);
Il écrit un composant dans le format binaire sur le flux. Par exemple :
procedure TForm1.Button1Click(Sender: TObject); var AStream: TMemoryStream; begin AStream:=TMemoryStream.Create; try WriteComponentAsBinaryToStream(AStream,AGroupBox); ... save stream somewhere ... finally AStream.Free; end; end;
Lecture d'un composant depuis un flux
L'unité LResources a une fonction pour cela :
procedure ReadComponentFromBinaryStream(AStream: TStream; var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);
- AStream est le flux contenant un composant au format binaire.
- RootComponent est soit un composant existant, dont les données seront écrasées, soit c'est nil et un nouveau composant sera créé.
- OnFindComponentClass est une fonction, qui est utilisée par TReader pour obtenir la classe à partir des noms de classe dans le flux. Par exemple :
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 est le propriétaire du composant , pendant la création d'un nouveau composant .
Propriétés pouvant être mise en flux
Il y a quelques limitations , sur les types TReader/TWriter qui peuvent être mis en flux:
- Les types de base peuvent être mis en flux: les châines de caractère, integer, char, single, double, extended, byte, word, cardinal, shortint, les pointeurs de méthode, etc. .
- TPersistent et ses descendants peuvent être mis en flux
- Les enregistrements(records), les objects et les classes ne descendant pas de TPersistent ne peut pas être mis en flux . Pour les mettre en flux vous devez dire à TReader/TWriter comment. Voir ci-dessous Mise en flux de données courantes - DefineProperties.
Mise en flux de données courantes - DefineProperties.
Vous pouvez mettre en flux des données arbitraires additionelles en écrasant DefineProperties. Ceci permet de mettre en flux toutes les données , qui n'ont aucun type de base. Par exemple pour mettre en flux une variable FMyRect: TRect de votre composant , ajouter les trois méthodes suivantes à votre composant :
procedure DefineProperties(Filer: TFiler); override; procedure ReadMyRect(Reader: TReader); procedure WriteMyRect(Writer: TWriter);
Avec le code suivant :
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;
Cela sauvegardera MyRect comme une propriété 'MyRect'.
Si vous mettez en flux beaucoup de TRect, alors vous ne voulez pas probablement écrire chaque fois ce code . L'unité LResources contient un exemple sur comment écrire une procédure pour définir une propriété rect :
procedure DefineRectProperty(Filer: TFiler; const Name: string; ARect, DefaultRect: PRect);
De cette façon le code ci-dessus peut être écrit ainsi brièvement :
procedure TMyComponent.DefineProperties(Filer: TFiler); begin inherited DefineProperties(Filer); DefineRectProperty(Filer,'MyRect',@FMyRect,nil); end;
Inscriture de votre propre composant - Partie 2
Maintenant l'exemple peut être prolongé et nous pouvons employer des propriétés arbitraires avec seulement quelques lignes de 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;
Ce composant peut maintenant être sauvegardé , chargé ou utilisé par Les contrôles RTTI. Vous n'avez pas besoin d'écrire tout autre code .
Ecrire et lire des composants depuis/vers XML
Mettre en flux des composants est simple : Voir l'exemple dans lazarus/examples/xmlstreaming/.
Conclusion
RTTI est un mécanisme puissant, qui peut être employé pour facilement mettre en flux des classes entières et aide à éviter d'écrite beaucoup de code de chargement/sauvegarde ennuyeux.
Voir également