I found a strange issue with a custom component that creates/destroys subcomponents dynamically.
type
TPanelTest = class(TPanel)
private
FShowPanel : Boolean;
FPanel : TPanel;
function GetShowPanel: Boolean;
procedure SetShowPanel(const Value: Boolean);
procedure CreateSubPanel;
procedure DestroySubPanel;
protected
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property ShowPanel : Boolean read GetShowPanel write SetShowPanel;
end;
...
{ TPanelTest }
constructor TPanelTest.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
SetBounds(0, 0, 300, 300);
ShowPanel := True;
end;
procedure TPanelTest.CreateSubPanel;
begin
if not Assigned(FPanel) then
begin
FPanel := TPanel.Create(Self);
with FPanel do
begin
SetSubComponent(True);
Parent := Self;
Caption := '';
Top := 0;
Left := 0;
Height := 50;
Align := alTop;
end;
end;
end;
procedure TPanelTest.DestroySubPanel;
begin
if Assigned(FPanel) then
FreeAndNil(FPanel);
end;
function TPanelTest.GetShowPanel: Boolean;
begin
Result := FShowPanel;
end;
procedure TPanelTest.SetShowPanel(const Value: Boolean);
begin
FShowPanel := Value;
if Value then
CreateSubPanel
else
DestroySubPanel;
end;
In run-time and design-time, everything (creating and destroying FPanel
) works correct, but if I set ShowPanel
to False, then save the project, close and open it again, I get an error:
Error creating form: Access violation at address 50CF4B9C in module 'vcl270.bpl'. Read of address 00000000.
If I manually change ShowPanel
to True in the .dfm
file, everything starts work correct again.
So, what am I missing? I'm using Delphi 10.4.2 CE
For now, I use a workaround with making SubPanel
invisible instead of destroying it, but I want to make this right.
Problem was in SetSubComponent(True)
:
...Unlike top-level components, subcomponents are not saved with the form or data module in which they reside. Instead, a subcomponent appears as the value of a published property of its Owner, and its published properties and events are saved in the form file with the owning component.
In this case, I don't need to set FPanel
as a SubComponent of TPanelTest
.