I have a container control which is TFramedScrollBox
. This in turn contains TFlowLayout
which in turn contains TPanel
and TRectangle
in them.
Again TPanel
can contain other controls like Edit Box, Combo Box, etc.
So the hierarchy is like this:
TFramedScrollBox
|->TFlowLayout
|-> TPanel
| |-> EditBox
| |-> ComboBox
| |-> DateTime Picker
| |-> Label
| |-> CheckBox
| |-> Radio Buttons
| |-> ListBox
|-> TRectangle
Actually all the controls in TFramedScrollBox
(except for TRectangle
) are created dynamically at runtime. At time of creation I am attaching events to each control as necessary based on different criteria.
Here is the code that I use to attache events to controls are time of creation:
pnlNewRow.OnClick := RowClick;
pnlNewRow.OnMouseEnter := RowMouseEnter;
pnlNewRow.OnMouseLeave := RowMouseLeave;
pnlNewRow.OnDblClick := RowDblClick;
I want to save all the controls in the container control will its sub components & sub-sub components along with events attached to each control in a field in SQLite. And in future load all the components form SQLite and create them on form.
I tried to serialize the container component but only the components are getting serialized and the events attached to it are not getting serialized.
Here is the code snippet that I am using to serialize components:
procedure TfrmMain.Button1Click(Sender: TObject);
var
MS: TMemoryStream;
TS: TStringStream;
begin
MS := TMemoryStream.Create;
MS.WriteComponent(sbMain);
MS.Position := 0;
TS := TStringStream.Create;
ObjectBinaryToText(MS, TS);
TS.Position := 0;
ShowMessage(TS.DataString);
end;
Please guide as to how I can save all the events a component is linked to and also the custom properties (that I plan to add in future) that are attached to it.
Please compile and run this minimal FMX project
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
protected
public
end;
[...]
function ComponentToString(AComponent : TComponent) : String;
var
SS : TStringStream;
MS : TMemoryStream;
Writer : TWriter;
begin
SS := TStringStream.Create('');
MS := TMemoryStream.Create;
Writer := TWriter.Create(MS, 4096);
try
Writer.Root := AComponent;
Writer.WriteSignature;
Writer.WriteComponent(AComponent);
Writer.FlushBuffer;
MS.Position := 0;
ObjectBinaryToText(MS, SS);
Result := SS.DataString;
finally
Writer.Free;
SS.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.Text := ComponentToString(Form1);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
//
end;
end.
Clicking Button1 writes this to Memo1:
object Form1: TForm1
Left = 224
[...]
OnCreate = FormCreate
OnDestroy = FormDestroy
DesignerMasterStyle = 0
[...]
object Button1: TButton
IsPressed = True
[...]
OnClick = Button1Click
end
object Memo1: TMemo
[...]
end
end
which, as you can see, includes the two event handlers of Form1 and the single one of Button1 and is like what the .DFM would contain. Isn't that what you were asking for?
And since you can store ComponentToString
as a library routine, I'm not sure it is correct to say "to serialize events you need to manually write code", well, not form-specific code anyway.
Btw, this works fine with dynamically created controls. Add a TButton, called Button, in the Private, Protected or Public section of the form and the following code to the FormCreate handler
procedure TForm1.FormCreate(Sender: TObject);
begin
Button := TButton.Create(Self);
Button.Name := 'Button';
Button.Parent := Self;
Button.OnClick := Button1Click;
end;
Clicking either button produces a similar list as the one above, but with the addition of the extra, dynamically created, button.