Search code examples
delphicomponentstype-conversionlazarus

Component to string in Lazarus


I made program according to these instructions. Works great, but I do not know why.

http://docwiki.embarcadero.com/CodeExamples/XE3/en/ComponentToString_(Delphi).

My code is:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Image1: TImage;
    Image2: TImage;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

function ComponentToStringProc(Component: TComponent): string;
var
  BinStream:TMemoryStream;
  StrStream: TStringStream;
  s: string;
begin
  BinStream := TMemoryStream.Create;
  try
    StrStream := TStringStream.Create(s);
    try
      BinStream.WriteComponent(Component);
      BinStream.Seek(0, soFromBeginning);
      ObjectBinaryToText(BinStream, StrStream);
      StrStream.Seek(0, soFromBeginning);
      Result:= StrStream.DataString;
    finally
      StrStream.Free;
    end;
  finally
    BinStream.Free
  end;
end;

function StringToComponentProc(Value: string): TComponent;
var
  StrStream:TStringStream;
  BinStream: TMemoryStream;
begin
  StrStream := TStringStream.Create(Value);
  try
    BinStream := TMemoryStream.Create;
    try
      ObjectTextToBinary(StrStream, BinStream);
      BinStream.Seek(0, soFromBeginning);
      Result:= BinStream.ReadComponent(nil);
    finally
      BinStream.Free;
    end;
  finally
    StrStream.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Text:= ComponentToStringProc(Image1);
end;

procedure TForm1.Button2Click(Sender: TObject);
var img:TImage;
begin
  img:= (StringToComponentProc(Memo1.Text) as TImage);
  img.Left:=200;
  img.Top:=96;
  img.Parent:=form1;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Picture.Bitmap.Height:=Image1.Height;
  Image1.Picture.Bitmap.Width:=Image1.Width;
  Image1.Picture.Bitmap.Canvas.Rectangle(0,0,Image1.Width,Image1.Height);
end;
initialization

RegisterClass(TImage);
end.

My question is: Why do I have

initialization


RegisterClass (TImage);

When Image2 is a visual component placed on form1?

If there's two lines are missing, it says error 219 Invalid typecast


Solution

  • The streaming framework needs to be able to convert a component class name into a class. Once it has done so it is able to instantiate an object of the right class.

    The key line of code is:

    Result := BinStream.ReadComponent(nil);
    

    Although Result has type TComponent, the actual runtime type can be a subclass of TComponent. In your case, TImage.

    So, in order to be able to convert the string 'TImage' into the meta class TImage, there needs to be a registry (i.e. a map) of classes and their names. And that registry is populated by calls to RegisterClass. Without that call, the streaming framework cannot find the metaclass TImage that is named 'TImage'. And so it cannot stream in the component.

    Although you are working with FPC, the Delphi documentation for RegisterClass will be helpful to you.