Difference between revisions of "Streaming components/fr"

From Free Pascal wiki
Jump to navigationJump to search
 
(38 intermediate revisions by 3 users not shown)
Line 3: Line 3:
 
== Introduction ==
 
== 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é.
+
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 , cela peut être chargé et sauvé à partir de flux sans charge supplémentaire de code de chargement/sauvegarde en utilisant la RTTI.
+
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'''.
  
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 .
+
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/
  Voir <lazaruspath>/examples/componentstreaming/
 
  
En combination avec
+
En combinaison avec [[RTTI controls/fr|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.
[[RTTI controls/fr|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 ==
 
== 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 .
+
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''' 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.
+
'''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 ==
  
Ce sont les classes qui travaillent, qui lisent/écrivent un TComponent vers/depuis un flux (Voir CreateLRSReader et CreateLRSWriter).
+
Ce sont les classes qui permettent d'écrire/de lire 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.
+
Elles emploient un '''Pilote''' pour lire/écrire dans un format spécial. A l'heure actuelle, il y a un lecteur ('''TLRSObjectReader'''), un  outil d'écriture ('''TLRSObjectWriter''') pour le format d'objet binaire défini dans l'unité '''LResources''' et un outil d'écriture ('''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.
+
L'unité '''LResources''' contient également des fonctions pour convertir le format binaire en texte et l'inverse ('''LRSObjectBinaryToText''', '''LRSObjectTextToBinary'''). La bibliothèque LCL utilise de préférence le codage '''UTF8''' pour les chaînes de caractères tandis que Delphi préfère '''Widestrings''' . Par conséquent, vous disposez aussi de quelques fonctions de conversion si bien que vous pouvez tout aussi bien travailler avec des données de flux provenant de Lazarus qu'avec des données au format binaire de Delphi.
  
== Writing your own component - Part 1 ==
+
== Streaming Collections ==
  
A custom component can be as simple as:  
+
Consultez [[TCollection/fr#Streaming]]
type
+
 
 +
Il s'agit d'un exemple complet qui montre comment utiliser les classes '''TCollectionItem''', '''TCollection''' et les gérer par des flux grâce à '''TComponent'''.
 +
 
 +
== Écrire votre propre composant  - Partie  1 ==
 +
 
 +
Un composant personnalisé peut être aussi simple que :
 +
 +
type
 
   TMyComponent = class(TComponent)
 
   TMyComponent = class(TComponent)
 
   private
 
   private
Line 35: Line 40:
 
   end;
 
   end;
  
== Writing a component to a stream ==
+
== Écrire un composant dans un flux ==
  
The unit [[doc:lcl/lresources|LResources]] has a function for that:  
+
L'unité [[doc:lcl/lresources|LResources]] a une fonction pour cela :  
 
   procedure WriteComponentAsBinaryToStream(AStream: TStream; AComponent: TComponent);
 
   procedure WriteComponentAsBinaryToStream(AStream: TStream; AComponent: TComponent);
  
It writes a component in binary format to the stream.
+
Elle écrit un composant dans le format binaire du flux.
For example:
+
Par exemple :
 
<pre>
 
<pre>
 
procedure TForm1.Button1Click(Sender: TObject);
 
procedure TForm1.Button1Click(Sender: TObject);
Line 50: Line 55:
 
   try
 
   try
 
     WriteComponentAsBinaryToStream(AStream,AGroupBox);
 
     WriteComponentAsBinaryToStream(AStream,AGroupBox);
     ... save stream somewhere ...
+
     ... enregistre le flux quelque part ...
 
   finally
 
   finally
 
     AStream.Free;
 
     AStream.Free;
Line 57: Line 62:
 
</pre>
 
</pre>
  
== Reading a component from a stream ==
+
== Lecture d'un composant depuis un flux  ==
  
The unit LResources has a function for that:  
+
L'unité '''LResources''' a une fonction pour cela :  
 
   procedure ReadComponentFromBinaryStream(AStream: TStream;
 
   procedure ReadComponentFromBinaryStream(AStream: TStream;
 
     var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);
 
     var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);
  
* AStream is the stream containing a component in binary format.
+
* '''AStream''' est le flux contenant un composant au format binaire.
* RootComponent is either an existing component, which data will be overwritten, or it is nil and a new component will be created.
+
* '''RootComponent''' est soit un composant existant dont les données seront écrasées, soit c'est '''nil''' et un nouveau composant sera créé.
* OnFindComponentClass is a function, that is used by TReader to get the class from the classnames in the stream. For example:
+
* '''OnFindComponentClass''' est une fonction qui est utilisée par '''TReader''' pour obtenir la classe à partir des noms de classe dans le flux. Par exemple :
 
<pre>
 
<pre>
 
procedure TCompStreamDemoForm.OnFindClass(Reader: TReader;
 
procedure TCompStreamDemoForm.OnFindClass(Reader: TReader;
Line 76: Line 81:
 
end;
 
end;
 
</pre>
 
</pre>
* TheOwner is the component owner, when creating a new component.
+
* '''TheOwner''' est le propriétaire du composant pendant la création d'un nouveau composant.
 
 
== Streamable properties ==
 
  
There are some limitations, what types TReader/TWriter can stream:
+
== Propriétés pouvant être stockées dans un flux ==
  
* Base types can be streamed: string, integer, char, single, double, extended, byte, word, cardinal, shortint, method pointers, etc. .
+
Il y a quelques limitations concernant les types '''TReader'''/'''TWriter''' qui peuvent être stockés dans un flux :
* 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]].
+
* Les types de base sont admis pour un flux : string, integer, char, single, double, extended, byte, word, cardinal, shortint, les pointeurs de méthode, etc. ;
 +
* '''TPersistent''' et ses descendants sont aussi admis pour un flux ;
 +
* Les enregistrements ('''records'''), les objets et les classes ne descendant pas de '''TPersistent''' ne peuvent pas être stockés dans un flux . Pour les stocker dans un flux, vous devez surcharger certaines méthodes de '''TReader'''/'''TWriter'''. Voir ci-dessous [[#Streaming custom Data - DefineProperties|Mise en flux de données courantes - DefineProperties]].
  
== Streaming custom Data - DefineProperties ==
+
== Mise en flux de données courantes - 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:
+
Vous pouvez mettre en flux des données arbitraires additionnelles 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 , ajoutez les trois méthodes suivantes à votre composant :
 
<pre>
 
<pre>
 
procedure DefineProperties(Filer: TFiler); override;
 
procedure DefineProperties(Filer: TFiler); override;
Line 96: Line 100:
 
</pre>
 
</pre>
  
With the following code:
+
avec le code suivant :
  
 
<pre>
 
<pre>
Line 136: Line 140:
 
</pre>
 
</pre>
  
This will save MyRect as a property 'MyRect'.
+
Cela sauvegardera '''MyRect''' en tant que propriété '''MyRect'''.
  
If you stream a lot of TRect, then you probably do not want to write everytime ths code.
+
Si vous mettez en flux beaucoup de '''TRect''', vous ne voudrez probablement pas écrire ce code chaque fois.
The unit LResources contains an example how to write a procedure to define a rect property:
+
L'unité '''LResources''' contient un exemple qui montre comment écrire une procédure pour définir une propriété '''rect''' :
 
   procedure DefineRectProperty(Filer: TFiler; const Name: string; ARect, DefaultRect: PRect);
 
   procedure DefineRectProperty(Filer: TFiler; const Name: string; ARect, DefaultRect: PRect);
 
    
 
    
This way the above code can be written this short:
+
De cette façon, le code ci-dessus peut être réduit à :
 
<pre>
 
<pre>
 
procedure TMyComponent.DefineProperties(Filer: TFiler);
 
procedure TMyComponent.DefineProperties(Filer: TFiler);
Line 151: Line 155:
 
</pre>
 
</pre>
  
== Writing your own component - Part 2 ==
+
== Écrire votre propre composant  - Partie  2 ==
  
Now the example can be extended and we can use arbitrary properties with only a few lines of code:
+
L'exemple décrit peut être étendu. Ainsi, nous pouvons employer des propriétés arbitraires avec seulement quelques lignes de code :
 
<pre>
 
<pre>
 
type
 
type
Line 178: Line 182:
 
</pre>
 
</pre>
  
This component can now be saved, loaded or used by the
+
Ce composant peut maintenant être sauvegardé, chargé ou utilisé par [[RTTI controls/fr|Les contrôles RTTI]].
[[RTTI controls/fr|Les contrôles RTTI]]. You don't need to write any further code.
+
Vous n'avez pas besoin d'écrire quoi que ce soit d'autre.
 +
 
 +
== Écrire et lire des composants depuis/vers LFM ==
 +
 
 +
Consultez les fonctions '''ReadComponentFromTextStream''' et '''WriteComponentAsTextToStream''' de l'unité '''lresources''' pour des exemples.
 +
 
 +
== Écrire et lire des composants depuis/vers XML ==
 +
 
 +
Mettre en flux des composants est simple :
 +
Consultez l'exemple dans lazarus/examples/xmlstreaming/.
 +
 
 +
== Noms ==
 +
 
 +
* Tous les composants appartenant à un composant ('''Owner''') doivent porter des noms distincts. Il en est de même pour deux fiches possédées par une application ou de deux étiquettes ('''labels''') d'une fiche. Mais deux étiquettes appartenant à deux fiches distinctes peuvent porter le même nom et une fiche peut porter le même nom qu'un de ses enfants.
 +
 
 +
* '''TComponent.Name''' peut rester vide et vous pouvez avoir plus d'un composant sans nom. '''TWriter''' écrira la propriété, mais '''TReader''' ne trouvera pas le composant en question si bien que la lecture échouera. Par conséquent, l'inspecteur d'objet de l'EDI ne tolère pas cette situation.
 +
 
 +
* Les noms doivent être des identificateurs Pascal corrects ([http://lazarus-ccr.sourceforge.net/docs/rtl/sysutils/isvalidident.html IsValidIdent]).
 +
 
 +
* Lors d'une référence à d'autres fiches, tous les composants racines ('''forms''', '''datamodules''', ...) référencés eux-mêmes par d'autres ('''forms''', etc.) doivent porter des noms uniques. Ils n'ont pas besoin d'être possédés par l'application, mais le programmeur doit alors par lui-même vérifier que leurs noms sont uniques. Les fiches et les modules de données peuvent être retrouvés grâce à l'objet '''Screen''' dans lequel toutes les fiches et tous les modules de données s'enregistrent automatiquement..
 +
 
 +
* Vous pouvez créer de nombreuses fiches portant le nom '''Form1''' (par exemple, grâce à '''TForm1.Create(nil)'''). Si une '''Form2''' fait référence à '''Form1.OpenDialog''', la première '''Form1''' dans '''Screen''' sera utilisée.
 +
 
 +
* Une fiche '''Form1''' et un cadre imbriqué peuvent posséder tous les deux un enfant '''Label1'''. Quand l'étiquette '''Label1''' sera référencée, ce sera de manière univoque pour la fiche entière, donc en incluant les cadres imbriqués. Il est par conséquent vivement recommandé de donner un nom unique à chaque élément.
  
== Writing and Reading components from/to XML ==
+
* Correction globale : '''TReader''' lit le flux d'un composant. S'il rencontre un cadre imbriqué, un second '''TReader''' est créé afin d'en lire le flux. Ensuite, le lecteur retourne à son point de départ et continue la lecture. Les référence à d'autres composants (par exemple '''Form1.Button1''') sont enregistrées dans une liste de correction dans les classes des unités (Voir [http://lazarus-ccr.sourceforge.net/docs/rtl/classes/getfixupreferencenames.html GetFixupReferenceNames]). Les références sont rectifiées après la lecture.
  
Streaming components is simple:
+
* '''TReader''' et '''TWriter''' utilisent le nom spécial '''Owner''' pour se référer au propriétaire en cours.
See the example in lazarus/examples/xmlstreaming/.
 
  
 
== Conclusion ==
 
== 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.
+
La RTTI est un mécanisme puissant qui peut être employé pour facilement mettre en flux des classes entières et qui évite d'écrire beaucoup de code de chargement/enregistrement pénible.
  
Voir également  
+
Voir également :
  
 
[[RTTI controls/fr|Les contrôles RTTI]]
 
[[RTTI controls/fr|Les contrôles RTTI]]

Latest revision as of 09:38, 30 May 2017

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 permettent d'écrire/de lire un TComponent vers/depuis un flux (Voir CreateLRSReader et CreateLRSWriter). Elles emploient un Pilote pour lire/écrire dans un format spécial. A l'heure actuelle, il y a un lecteur (TLRSObjectReader), un outil d'écriture (TLRSObjectWriter) pour le format d'objet binaire défini dans l'unité LResources et un outil d'écriture (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 utilise de préférence le codage UTF8 pour les chaînes de caractères tandis que Delphi préfère Widestrings . Par conséquent, vous disposez aussi de quelques fonctions de conversion si bien que vous pouvez tout aussi bien travailler avec des données de flux provenant de Lazarus qu'avec des données au format binaire de Delphi.

Streaming Collections

Consultez TCollection/fr#Streaming

Il s'agit d'un exemple complet qui montre comment utiliser les classes TCollectionItem, TCollection et les gérer par des flux grâce à TComponent.

Écrire votre propre composant - Partie 1

Un composant personnalisé peut être aussi simple que :

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

Écrire un composant dans un flux

L'unité LResources a une fonction pour cela :

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

Elle écrit un composant dans le format binaire du flux. Par exemple :

procedure TForm1.Button1Click(Sender: TObject);
var
  AStream: TMemoryStream;
begin
  AStream:=TMemoryStream.Create;
  try
    WriteComponentAsBinaryToStream(AStream,AGroupBox);
    ... enregistre le flux quelque part ...
  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 stockées dans un flux

Il y a quelques limitations concernant les types TReader/TWriter qui peuvent être stockés dans un flux :

  • Les types de base sont admis pour un flux : string, integer, char, single, double, extended, byte, word, cardinal, shortint, les pointeurs de méthode, etc. ;
  • TPersistent et ses descendants sont aussi admis pour un flux ;
  • Les enregistrements (records), les objets et les classes ne descendant pas de TPersistent ne peuvent pas être stockés dans un flux . Pour les stocker dans un flux, vous devez surcharger certaines méthodes de TReader/TWriter. 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 additionnelles 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 , ajoutez 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 en tant que propriété MyRect.

Si vous mettez en flux beaucoup de TRect, vous ne voudrez probablement pas écrire ce code chaque fois. L'unité LResources contient un exemple qui montre 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 réduit à :

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

Écrire votre propre composant - Partie 2

L'exemple décrit peut être étendu. Ainsi, 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 quoi que ce soit d'autre.

Écrire et lire des composants depuis/vers LFM

Consultez les fonctions ReadComponentFromTextStream et WriteComponentAsTextToStream de l'unité lresources pour des exemples.

Écrire et lire des composants depuis/vers XML

Mettre en flux des composants est simple : Consultez l'exemple dans lazarus/examples/xmlstreaming/.

Noms

  • Tous les composants appartenant à un composant (Owner) doivent porter des noms distincts. Il en est de même pour deux fiches possédées par une application ou de deux étiquettes (labels) d'une fiche. Mais deux étiquettes appartenant à deux fiches distinctes peuvent porter le même nom et une fiche peut porter le même nom qu'un de ses enfants.
  • TComponent.Name peut rester vide et vous pouvez avoir plus d'un composant sans nom. TWriter écrira la propriété, mais TReader ne trouvera pas le composant en question si bien que la lecture échouera. Par conséquent, l'inspecteur d'objet de l'EDI ne tolère pas cette situation.
  • Les noms doivent être des identificateurs Pascal corrects (IsValidIdent).
  • Lors d'une référence à d'autres fiches, tous les composants racines (forms, datamodules, ...) référencés eux-mêmes par d'autres (forms, etc.) doivent porter des noms uniques. Ils n'ont pas besoin d'être possédés par l'application, mais le programmeur doit alors par lui-même vérifier que leurs noms sont uniques. Les fiches et les modules de données peuvent être retrouvés grâce à l'objet Screen dans lequel toutes les fiches et tous les modules de données s'enregistrent automatiquement..
  • Vous pouvez créer de nombreuses fiches portant le nom Form1 (par exemple, grâce à TForm1.Create(nil)). Si une Form2 fait référence à Form1.OpenDialog, la première Form1 dans Screen sera utilisée.
  • Une fiche Form1 et un cadre imbriqué peuvent posséder tous les deux un enfant Label1. Quand l'étiquette Label1 sera référencée, ce sera de manière univoque pour la fiche entière, donc en incluant les cadres imbriqués. Il est par conséquent vivement recommandé de donner un nom unique à chaque élément.
  • Correction globale : TReader lit le flux d'un composant. S'il rencontre un cadre imbriqué, un second TReader est créé afin d'en lire le flux. Ensuite, le lecteur retourne à son point de départ et continue la lecture. Les référence à d'autres composants (par exemple Form1.Button1) sont enregistrées dans une liste de correction dans les classes des unités (Voir GetFixupReferenceNames). Les références sont rectifiées après la lecture.
  • TReader et TWriter utilisent le nom spécial Owner pour se référer au propriétaire en cours.

Conclusion

La RTTI est un mécanisme puissant qui peut être employé pour facilement mettre en flux des classes entières et qui évite d'écrire beaucoup de code de chargement/enregistrement pénible.

Voir également :

Les contrôles RTTI