Create DELPHI Component at Runtime

Asked

Viewed 887 times

1

texto := 'object DWResponseTranslator1: TDWResponseTranslator ' +
  'ElementAutoReadRootIndex = True'+
  'ElementRootBaseIndex = -1'+
  'RequestOpen = rtGet'+
  'RequestInsert = rtPost'+
  'RequestEdit = rtPost'+
  'RequestDelete = rtDelete'+
  'FieldDefs = <'+  
  '  item'+
  '    FieldName = 'ID''+
  '    ElementName = 'ID''+
  '    ElementIndex = -1'+
  '    FieldSize = 6'+
  '    Precision = 0'+
  '    DataType = ovInteger'+
  '    Required = False'+
  '  end'+  
  'left = 288'+
  'top = 32'+
  'end';

novoComponente := Criar_Componente(Texto);

I have this structure copied from a designer compontente it is possible with this text to create a Delphi component at execution time ??

  • 1

    As already answered by @Roberto, you need to create the class in hand and set the properties as desired. A solution to automate a little this process would be using the plugin Gexperts, have an option to right-click mouse and "Component to code", it already returns all the necessary code.

3 answers

1

To create component at runtime, I do it as follows:

var
  DWResponseTranslator1: TDWResponseTranslator;
begin
  DWResponseTranslator1 := TDWResponseTranslator.Create({Aqui é necessário colocar os parâmetros de construção});
  DWResponseTranslator1.ElementAutoReadRootIndex := True;
  DWResponseTranslator1.ElementRootBaseIndex := -1;

  ...

end;

In the case of property FieldDefs a Field at a time and add to the FieldDefs.

1

To extract DFM code from a component:

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;

To create component from DFM code:

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;

To use do the following:

Get the DFM code from an Edit;

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

To create Edit from the downloaded DFM:

procedure TForm1.Button7Click(Sender: TObject);
var
  EdtX: TEdit;
begin
  EdtX := StringToComponentProc(Memo1.Text) as TEdit;
  EdtX.Parent := Form1;
end;

No initialization register the Tedit class or components you want.

initialization
  RegisterClass(TEdit);

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

0

Based on the pure string you can implement as you need other classes to appear.

In the following example I am considering creating a component based on TEdit precisely because it does not have this component that it demonstrated in the question, but the idea is the same.

function TForm14.Criar_Componente(aComponente: String): TComponent;
var
  vComponente : TArray<String>;
begin
  aComponente := aComponente.Substring(0, aComponente.Length - 3);
  vComponente := aComponente.Split([' ']);

  if (vComponente[2] = 'TEdit') then
  begin
    TEdit(Result)          := TEdit.Create(Self);
    TEdit(Result).Parent   := Self;
    TEdit(Result).Name     := vComponente[1].Replace(':', EmptyStr);
    TEdit(Result).Left     := StrToInt(vComponente[6]);
    TEdit(Result).Top      := StrToInt(vComponente[10]);
    TEdit(Result).Width    := StrToInt(vComponente[14]);
    TEdit(Result).Height   := StrToInt(vComponente[18]);
    TEdit(Result).TabOrder := StrToInt(vComponente[22]);
    TEdit(Result).Text     := vComponente[26];
  end;
end;

The Split([' ']); will give you an array of data, just take each position equivalent to each property, that is "procedural", I know no other way.

As the result of the function is a TComponente it will suit most classes.

You can create overloads for different classes if you wish.

Enough to use:

var
  vComponente : TComponent;
const
  _COMPONENTE =   'object Lb_Teste: TEdit'+
                  '  Left = 402'+
                  '  Top = 8'+
                  '  Width = 225'+
                  '  Height = 21'+
                  '  TabOrder = 0'+
                  '  Text = ''Teste'+
                  'end';
begin
  vComponente := Criar_Componente(_COMPONENTE);
end;

Browser other questions tagged

You are not signed in. Login or sign up in order to post.