Difference between revisions of "Streaming components/pl"

From Free Pascal wiki
Jump to navigationJump to search
(→‎TComponent / TPersistent: tłumaczenie na j. polski)
m (→‎Streaming Collections: tłumaczenie tytułu na j. polski)
 
(16 intermediate revisions by the same user not shown)
Line 18: Line 18:
 
== TReader / TWriter ==
 
== TReader / TWriter ==
  
TReader and TWriter are worker classes, which read or write any TComponent to or from a stream (See CreateLRSReader and CreateLRSWriter).
+
TReader i TWriter to klasy robocze, które odczytują ze strumienia lub zapisują do strumienia dowolny składnik TComponent (patrz CreateLRSReader i CreateLRSWriter).
They use a '''Driver''' to read/write using a special data format. At the moment there is a reader (TLRSObjectReader) and a writer (TLRSObjectWriter) for binary object format defined in the LResources unit, and a writer (TXMLObjectWriter) for TDOMDocument defined in Laz_XMLStreaming.
+
Używają one '''Driver''' do odczytu/zapisu przy użyciu specjalnego formatu danych. W tej chwili istnieje czytnik (TLRSObjectReader) i moduł zapisujący (TLRSObjectWriter) dla formatu obiektu binarnego zdefiniowanego w jednostce LResources oraz moduł zapisujący (TXMLObjectWriter) dla TDOMDocument zdefiniowany w Laz_XMLStreaming.
The LResources unit also contains functions to convert the custom binary data format to text and back (LRSObjectBinaryToText, LRSObjectTextToBinary). The LCL prefers UTF8 for strings, while Delphi prefers Widestrings. So there are some conversion functions provided as well so you can deal easily with streaming component data not only in Lazarus but using the Delphi binary format too.
+
Moduł LResources zawiera również funkcje do konwersji zwykłych formatu danych binarnych na tekst i z powrotem (LRSObjectBinaryToText, LRSObjectTextToBinary). LCL preferuje UTF8 dla łańcuchów, podczas gdy Delphi preferuje Widestrings. Zapewnia także pewne funkcje konwersji, dzięki czemu można łatwo poradzić sobie z przesyłaniem strumieniowym danych nie tylko w Lazarus, ale także w formacie binarnym Delphi.
  
== Streaming Collections ==
+
== Kolekcje strumieniowe ==
  
See it here [[TCollection#Streaming]]
+
Zobacz tutaj [[TCollection/pl#Przesyłanie strumieniowe]]
  
This is a full example how to create a list of items using the classes '''TCollectionItem''', '''TCollection''' and stream it using '''TComponent'''.
+
Jest to pełny przykład, jak utworzyć listę elementów za pomocą klas '''TCollectionItem''' i '''TCollection''', i przesyłać strumieniowo za pomocą '''TComponent'''.
  
== Writing your own component - Part 1 ==
+
== Zapisywanie własnego komponentu - Część 1 ==
  
A custom component can be as simple as:  
+
Własny komponent może być np. tak prosty, jak:  
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 42: Line 42:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Writing a component to a stream ==
+
== Zapisywanie komponentu do strumienia ==
  
The unit [[doc:lcl/lresources|LResources]] has a function for that:  
+
Moduł [[doc:lcl/lresources|LResources]] zawiera funkcję taką jak:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
 
procedure WriteComponentAsBinaryToStream(AStream: TStream; AComponent: TComponent);</syntaxhighlight>
 
procedure WriteComponentAsBinaryToStream(AStream: TStream; AComponent: TComponent);</syntaxhighlight>
  
It writes a component in binary format to the stream.
+
Która zapisuje komponent w formacie binarnym do strumienia.
For example:
+
Na przykład:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 67: Line 67:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Reading a component from a stream ==
+
== Odczytywanie komponentu ze strumienia ==
  
The unit LResources has a function for that:  
+
Moduł LResources zawiera funkcję taką jak:  
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 75: Line 75:
 
     var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);</syntaxhighlight>
 
     var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);</syntaxhighlight>
  
* AStream is the stream containing '''one''' component in binary format. Everything behind that component in the stream is not read, including other components.
+
* AStream to strumień zawierający '''jeden''' komponent w formacie binarnym. Wszystko za tym komponentem w strumieniu nie jest odczytywane, w tym inne komponenty.
* RootComponent is either an existing component, which data will be overwritten, or it is nil and a new component will be created.
+
* RootComponent zawiera istniejący komponent, którego dane zostaną nadpisane, lub ma wartość nil i zostanie utworzony nowy komponent.
* OnFindComponentClass is a function, that is used by TReader to get the class from the classnames in the stream. For example:
+
* OnFindComponentClass to funkcja używana przez TReader do pobierania klasy z nazw klas w strumieniu. Na przykład:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 90: Line 90:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
* TheOwner is the component owner, when creating a new component.
+
* TheOwner jest właścicielem komponentu podczas tworzenia nowego komponentu.
  
== Streamable properties ==
+
== Właściwości strumieniowalne ==
  
TReader and TWriter have several limitations on what types they can stream:
+
TReader i TWriter mają kilka ograniczeń co do typów, które mogą przesyłać strumieniowo:
  
* All basic Pascal types can be streamed: string, integer, char, single, double, extended, byte, word, cardinal, shortint, method pointers, etc.
+
* Wszystkie podstawowe typy Pascala mogą być przesyłane strumieniowo: string, integer, char, single, double, extended, byte, word, cardinal, shortint, method pointers, itp.
  
* Any TPersistent class and any TPersistent descendant can be streamed
+
* Każda klasa TPersistent i dowolny potomek TPersistent mogą być przesyłane strumieniowo
  
* Records, objects and classes not descending from TPersistent cannot be streamed without extending existing TReader/TWriter methods. To stream records or non-TPersistent classes and objects you need to override certain TReader/TWriter methods. See below [[#Streaming custom Data - DefineProperties]].
+
* Rekordy, obiekty i klasy nie pochodzące od TPersistent nie mogą być przesyłane strumieniowo bez rozszerzenia istniejących metod TReader/TWriter. Aby przesyłać strumieniowo rekordy lub klasy i obiekty nie-TPersistent, musisz przesłonić niektóre metody TReader/TWriter. Zobacz poniżej [[#Streaming custom Data - DefineProperties]].
  
== Streaming custom Data - DefineProperties ==
+
== Strumieniowanie danych niestandardowych - DefineProperties ==
  
You can stream additional arbitrary data by overriding DefineProperties. This allows you to stream data that is not a basic Pascal type, and classes that are not TPersistent descendants. For example to stream a record variable '''FMyRect: TRect''' which is a field in your component, add the following three methods to your component:
+
Możesz przesyłać strumieniowo dodatkowe dowolne dane, zastępując metodę DefineProperties. Umożliwia to przesyłanie strumieniowe danych, które nie są podstawowym typem Pascala, oraz klas, które nie są potomkami TPersistent. Na przykład, aby przesłać strumieniowo zmienną rekordu '''FMyRect: TRect''', która jest polem w twoim komponencie, dodaj do komponentu następujące trzy metody:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 112: Line 112:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
With the following code:
+
Z następującym kodem:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 152: Line 152:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This will save MyRect as a property 'MyRect'.
+
Spowoduje to zapisanie MyRect jako właściwości 'MyRect'.
  
If you stream a lot of TRect fields, then you probably don't want to repeat this code every time.
+
Jeśli przesyłasz strumieniowo wiele pól TRect, prawdopodobnie nie chcesz powtarzać tego kodu za każdym razem.
The unit LResources contains an example of how you can write a procedure that defines a rect property:
+
Moduł LResources zawiera przykład, w jaki sposób można napisać procedurę definiującą właściwość rect:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 161: Line 161:
 
</syntaxhighlight>
 
</syntaxhighlight>
 
    
 
    
Having written a procedure to define a rect property, the above code can be reduced to:
+
Po napisaniu procedury definiowania właściwości rect powyższy kod można sprowadzić do:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 171: Line 171:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Writing your own component - Part 2 ==
+
== Zapisywanie własnego komponentu - Część 2 ==
  
Now the example can be extended and we can use arbitrary properties with only a few lines of code:
+
Teraz przykład można rozszerzyć i możemy użyć dowolnych właściwości za pomocą tylko kilku wierszy kodu:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 199: Line 199:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This component can now be saved, loaded or used by the [[RTTI controls]]. You don't need to write any further code.
+
Ten komponent może teraz zostać zapisany, załadowany lub użyty przez [[RTTI controls|kontrolki RTTI]]. Nie musisz pisać żadnego kodu.
  
== Writing and Reading components from/to LFM ==
+
== Zapisywanie i odczytywanie komponentów z/do LFM ==
  
See unit lresources function ReadComponentFromTextStream and WriteComponentAsTextToStream for examples.
+
Zobacz przykładowe funkcje z modułu lresources: ReadComponentFromTextStream i WriteComponentAsTextToStream.
  
== Writing and Reading components from/to XML ==
+
== Zapisywanie i odczytywanie komponentów z/do XML ==
  
Streaming components is simple:
+
Przesyłanie strumieniem komponentów jest proste:
See the example in lazarus/examples/xmlstreaming/.
+
Zobacz przykład w lazarus/examples/xmlstreaming/.
  
== Names ==
+
== Nazwy ==
  
* All components of one component (Owner) must have distinct names. So two forms owned by applications must have distinct names. And two labels on a form must have distinct names. But two labels on two different forms can have the same name. And a form can have the same name as one of its children.
+
* Wszystkie komponenty należące do jednego komponentu (właściciela) muszą mieć odrębne nazwy. Tak więc dwa formularze będące własnością aplikacji muszą mieć odrębne nazwy. Dwie etykiety na formularzu muszą mieć różne nazwy. Ale dwie etykiety na dwóch różnych formularzach mogą mieć tę samą nazwę. Formularz może mieć takie samo imię jak jedno z jego dzieci.
  
* TComponent.Name can be empty and you can have more than one component without a name. TWriter will write it, but TReader will not find the component and reading will fail. Therefore the IDE's Object Inspector does not allow that.
+
* TComponent.Name może być pusta i można mieć więcej niż jeden komponent bez nazwy. TWriter zapisze to, ale TReader nie znajdzie takiego komponentu i odczyt się nie powiedzie. Dlatego Inspektor obiektów IDE nie pozwala na to.
  
* Names must be valid Pascal identifiers [http://lazarus-ccr.sourceforge.net/docs/rtl/sysutils/isvalidident.html IsValidIdent].
+
* Nazwy muszą być poprawnymi identyfikatorami Pascala [http://lazarus-ccr.sourceforge.net/docs/rtl/sysutils/isvalidident.html IsValidIdent].
  
* When referencing other forms: All root components (forms, datamodules, ...) referenced by other (forms,etc) must have unique names. They don't need to be owned by the application, but then the programmer himself must make sure the names are unique. Forms and Datamodules are found via the Screen object, where all forms and datamodules register themselves  automatically.
+
* Podczas odwoływania się do innych formularzy: Wszystkie komponenty główne (formularze, moduły danych, ...), do których odnoszą się inne (formularze itp.), muszą mieć unikalne nazwy. Nie muszą być własnością aplikacji, ale wtedy programista musi upewnić się, że nazwy są unikalne. Formularze i moduły danych znaleźć można za pośrednictwem obiektu Screen, w którym wszystkie formularze i moduły danych rejestrują się automatycznie.
  
* You can create many forms with the name Form1, for example via ''TForm1.Create(nil)''. If a ''Form2'' references a ''Form1.OpenDialog'', then the first ''Form1'' in ''Screen'' is used.
+
* Możesz utworzyć wiele formularzy o nazwie Form1, na przykład poprzez ''TForm1.Create(nil)''. Jeśli ''Form2'' odwołuje się do ''Form1.OpenDialog'', wówczas w obiekcie ''Screen'' jako pierwsza występuje ''Form1''.
  
* A ''Form1'' and an embedded frame can have both a child ''Label1''. When the ''Label1'' is referenced then it should be unique on the whole form including all embedded frames. So it is recommended to give all components unique names.
+
* ''Form1'' i osadzona w niej ramka ''frame'' mogą mieć jednocześnie etykiety o nazwie ''Label1''. Gdy pojawia się odniesienie do ''Label1'', powinna być ona unikalne w całym formularzu, w tym we wszystkich osadzonych ramkach. Dlatego zaleca się nadanie wszystkim komponentom unikalnych nazw.
  
* Global fixup: TReader reads a component stream. If it finds an embedded frame a second TReader is created, which reads the frame stream. Then it returns and continues. References to other components (e.g. ''Form1.Button1'') are saved to a global fixup list in the unit classes (see [http://lazarus-ccr.sourceforge.net/docs/rtl/classes/getfixupreferencenames.html GetFixupReferenceNames]). The references are fixed up after reading.
+
* Globalna poprawka: TReader odczytuje strumień komponentu. Jeśli znajdzie osadzoną ramkę (frame), tworzony jest drugi TReader, który odczytuje strumień ramek. Następnie powraca i kontynuuje. Odniesienia do innych komponentów (np. ''Form1.Button1'') są zapisywane na globalnej liście poprawek w module classes (patrz [http://lazarus-ccr.sourceforge.net/docs/rtl/classes/getfixupreferencenames.html GetFixupReferenceNames]). Odniesienia są poprawiane po odczytaniu.
  
* TReader and TWriter use the special name ''Owner'' to refer to the current Owner.
+
* TReader i TWriter używają specjalnej nazwy ''Owner'' do odniesienia się do aktualnego właściciela.
  
== Conclusion ==
+
== Wniosek ==
  
RTTI is a powerful mechanism for streaming entire classes easily. RTTI also helps you to avoid repeatedly writing a lot of boring load/save code.
+
RTTI to potężny mechanizm umożliwiający łatwe przesyłanie strumieniowe całych klas. RTTI pomaga również uniknąć wielokrotnego pisania nudnego kodu ładowania/zapisywania.
  
==See also==
+
==Zobacz także==
  
* [[RTTI controls]]
+
* [[RTTI controls|Kontrolki RTTI]]
* [[OpenGL Tutorial]]
+
* [[OpenGL Tutorial|Samouczek OpenGL]]

Latest revision as of 11:23, 31 January 2023

Deutsch (de) English (en) français (fr) 日本語 (ja) polski (pl) português (pt)

Wprowadzenie

Zwykle, gdy chcesz przechowywać dane na dysku lub w strumieniu sieciowym, musisz napisać kod, który ładuje i zapisuje każdą właściwość. W tym samouczku opisano, jak pisać klasy, które można ładować i zapisywać w strumieniach przy użyciu RTTI (RunTime Type Information) bez potrzeby pisania dodatkowego kodu ładowania/zapisywania.

Źródła Lazarus zawierają przykład, który pokazuje, jak zapisać TGroupBox z dzieckiem TCheckBox w strumieniu i jak ponownie odczytać strumień, aby odtworzyć kopię obu składników. Zobacz: <lazaruspath>/examples/componentstreaming/.

Łącząc użycie odpowiednich kontrolek RTTI, możesz zminimalizować ilość kodu potrzebnego do połączenia GUI programu z odpowiednimi danymi na pamięci dyskowej/sieciowej.

TComponent / TPersistent

Klasa TPersistent jest zdefiniowana w module Classes i wykorzystuje przełącznik kompilatora {$M+}. Ten przełącznik informuje kompilator o utworzeniu informacji o typie w czasie wykonywania programu (RTTI). Oznacza to, że klasy w tym module i wszystkie klasy potomne otrzymują nową sekcję klasową published. Właściwości published są tak samo widoczne, jak właściwości public, ale dodatkowo ich struktura jest dostępna w czasie wykonywania. Oznacza to, że wszystkie właściwości published mogą być odczytywane i zapisywane w czasie wykonywania. Na przykład IDE używa RTTI do pracy z komponentami, o których inaczej nic by nie wiedział.

TComponent rozszerza TPersistent o możliwość posiadania komponentów potomnych. Jest to ważne w przypadku przesyłania strumieniowego, gdzie jednym składnikiem jest root component (zwany także lookup root), zawierający listę komponentów potomnych.

TReader / TWriter

TReader i TWriter to klasy robocze, które odczytują ze strumienia lub zapisują do strumienia dowolny składnik TComponent (patrz CreateLRSReader i CreateLRSWriter). Używają one Driver do odczytu/zapisu przy użyciu specjalnego formatu danych. W tej chwili istnieje czytnik (TLRSObjectReader) i moduł zapisujący (TLRSObjectWriter) dla formatu obiektu binarnego zdefiniowanego w jednostce LResources oraz moduł zapisujący (TXMLObjectWriter) dla TDOMDocument zdefiniowany w Laz_XMLStreaming. Moduł LResources zawiera również funkcje do konwersji zwykłych formatu danych binarnych na tekst i z powrotem (LRSObjectBinaryToText, LRSObjectTextToBinary). LCL preferuje UTF8 dla łańcuchów, podczas gdy Delphi preferuje Widestrings. Zapewnia także pewne funkcje konwersji, dzięki czemu można łatwo poradzić sobie z przesyłaniem strumieniowym danych nie tylko w Lazarus, ale także w formacie binarnym Delphi.

Kolekcje strumieniowe

Zobacz tutaj TCollection/pl#Przesyłanie strumieniowe

Jest to pełny przykład, jak utworzyć listę elementów za pomocą klas TCollectionItem i TCollection, i przesyłać strumieniowo za pomocą TComponent.

Zapisywanie własnego komponentu - Część 1

Własny komponent może być np. tak prosty, jak:

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

Zapisywanie komponentu do strumienia

Moduł LResources zawiera funkcję taką jak:

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

Która zapisuje komponent w formacie binarnym do strumienia. Na przykład:

procedure TForm1.Button1Click(Sender: TObject);
var
  AStream: TMemoryStream;
begin
  AStream:=TMemoryStream.Create;
  try
    WriteComponentAsBinaryToStream(AStream, AGroupBox);
    ... save stream somewhere ...
  finally
    AStream.Free;
  end;
end;

Odczytywanie komponentu ze strumienia

Moduł LResources zawiera funkcję taką jak:

procedure ReadComponentFromBinaryStream(AStream: TStream;
    var RootComponent: TComponent; OnFindComponentClass: TFindComponentClassEvent; TheOwner: TComponent = nil);
  • AStream to strumień zawierający jeden komponent w formacie binarnym. Wszystko za tym komponentem w strumieniu nie jest odczytywane, w tym inne komponenty.
  • RootComponent zawiera istniejący komponent, którego dane zostaną nadpisane, lub ma wartość nil i zostanie utworzony nowy komponent.
  • OnFindComponentClass to funkcja używana przez TReader do pobierania klasy z nazw klas w strumieniu. Na przykład:
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 jest właścicielem komponentu podczas tworzenia nowego komponentu.

Właściwości strumieniowalne

TReader i TWriter mają kilka ograniczeń co do typów, które mogą przesyłać strumieniowo:

  • Wszystkie podstawowe typy Pascala mogą być przesyłane strumieniowo: string, integer, char, single, double, extended, byte, word, cardinal, shortint, method pointers, itp.
  • Każda klasa TPersistent i dowolny potomek TPersistent mogą być przesyłane strumieniowo
  • Rekordy, obiekty i klasy nie pochodzące od TPersistent nie mogą być przesyłane strumieniowo bez rozszerzenia istniejących metod TReader/TWriter. Aby przesyłać strumieniowo rekordy lub klasy i obiekty nie-TPersistent, musisz przesłonić niektóre metody TReader/TWriter. Zobacz poniżej #Streaming custom Data - DefineProperties.

Strumieniowanie danych niestandardowych - DefineProperties

Możesz przesyłać strumieniowo dodatkowe dowolne dane, zastępując metodę DefineProperties. Umożliwia to przesyłanie strumieniowe danych, które nie są podstawowym typem Pascala, oraz klas, które nie są potomkami TPersistent. Na przykład, aby przesłać strumieniowo zmienną rekordu FMyRect: TRect, która jest polem w twoim komponencie, dodaj do komponentu następujące trzy metody:

procedure DefineProperties(Filer: TFiler); override;
procedure ReadMyRect(Reader: TReader);
procedure WriteMyRect(Writer: TWriter);

Z następującym kodem:

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;

Spowoduje to zapisanie MyRect jako właściwości 'MyRect'.

Jeśli przesyłasz strumieniowo wiele pól TRect, prawdopodobnie nie chcesz powtarzać tego kodu za każdym razem. Moduł LResources zawiera przykład, w jaki sposób można napisać procedurę definiującą właściwość rect:

procedure DefineRectProperty(Filer: TFiler; const Name: string; ARect, DefaultRect: PRect);

Po napisaniu procedury definiowania właściwości rect powyższy kod można sprowadzić do:

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

Zapisywanie własnego komponentu - Część 2

Teraz przykład można rozszerzyć i możemy użyć dowolnych właściwości za pomocą tylko kilku wierszy kodu:

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;

Ten komponent może teraz zostać zapisany, załadowany lub użyty przez kontrolki RTTI. Nie musisz pisać żadnego kodu.

Zapisywanie i odczytywanie komponentów z/do LFM

Zobacz przykładowe funkcje z modułu lresources: ReadComponentFromTextStream i WriteComponentAsTextToStream.

Zapisywanie i odczytywanie komponentów z/do XML

Przesyłanie strumieniem komponentów jest proste: Zobacz przykład w lazarus/examples/xmlstreaming/.

Nazwy

  • Wszystkie komponenty należące do jednego komponentu (właściciela) muszą mieć odrębne nazwy. Tak więc dwa formularze będące własnością aplikacji muszą mieć odrębne nazwy. Dwie etykiety na formularzu muszą mieć różne nazwy. Ale dwie etykiety na dwóch różnych formularzach mogą mieć tę samą nazwę. Formularz może mieć takie samo imię jak jedno z jego dzieci.
  • TComponent.Name może być pusta i można mieć więcej niż jeden komponent bez nazwy. TWriter zapisze to, ale TReader nie znajdzie takiego komponentu i odczyt się nie powiedzie. Dlatego Inspektor obiektów IDE nie pozwala na to.
  • Nazwy muszą być poprawnymi identyfikatorami Pascala IsValidIdent.
  • Podczas odwoływania się do innych formularzy: Wszystkie komponenty główne (formularze, moduły danych, ...), do których odnoszą się inne (formularze itp.), muszą mieć unikalne nazwy. Nie muszą być własnością aplikacji, ale wtedy programista musi upewnić się, że nazwy są unikalne. Formularze i moduły danych znaleźć można za pośrednictwem obiektu Screen, w którym wszystkie formularze i moduły danych rejestrują się automatycznie.
  • Możesz utworzyć wiele formularzy o nazwie Form1, na przykład poprzez TForm1.Create(nil). Jeśli Form2 odwołuje się do Form1.OpenDialog, wówczas w obiekcie Screen jako pierwsza występuje Form1.
  • Form1 i osadzona w niej ramka frame mogą mieć jednocześnie etykiety o nazwie Label1. Gdy pojawia się odniesienie do Label1, powinna być ona unikalne w całym formularzu, w tym we wszystkich osadzonych ramkach. Dlatego zaleca się nadanie wszystkim komponentom unikalnych nazw.
  • Globalna poprawka: TReader odczytuje strumień komponentu. Jeśli znajdzie osadzoną ramkę (frame), tworzony jest drugi TReader, który odczytuje strumień ramek. Następnie powraca i kontynuuje. Odniesienia do innych komponentów (np. Form1.Button1) są zapisywane na globalnej liście poprawek w module classes (patrz GetFixupReferenceNames). Odniesienia są poprawiane po odczytaniu.
  • TReader i TWriter używają specjalnej nazwy Owner do odniesienia się do aktualnego właściciela.

Wniosek

RTTI to potężny mechanizm umożliwiający łatwe przesyłanie strumieniowe całych klas. RTTI pomaga również uniknąć wielokrotnego pisania nudnego kodu ładowania/zapisywania.

Zobacz także