0

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.

5
  • Welcome to Stack Overflow. If you set Showpanel to false, when you open the form, SetShowPanel tries to run DestroySubPanel; but FPanel was never created and so (iiuic), accessing FPanel chokes. Been some time since I've touched Delphi... Commented Jun 7, 2023 at 1:46
  • @ewokx No, I checked with simple logging - it creates FPanel when setting ShowPanel to True in constructor. On second step Delphi set properties from dfm and after that I get error. But I can't catch where error appears. And as I said when I play with setting ShowPanel to false and back to true runtime and design time (from object inspector) - everything is ok. Commented Jun 7, 2023 at 3:00
  • @Capricorn7B FYI, since you are setting ShowPanel=True in the constructor, you should add default True to the declaration of the ShowPanel property, eg: property ShowPanel : Boolean read GetShowPanel write SetShowPanel default True; Otherwise the DFM will think the default is False instead. Also, you don't need to check Assigned() before calling FreeAndNil(), it already handles that internally. Also, when you have design-time errors like this, you can run a 2nd instance of the IDE to debug the 1st instance so you can step through your code at design-time. Commented Jun 7, 2023 at 15:58
  • @Capricorn7B for future reference, please don't edit your questions to post solutions. That is what posting answers is meant for instead. stackoverflow.com/help/self-answer Commented Jun 7, 2023 at 16:12
  • @RemyLebeau Sorry, I thought that I save other people's time this way. I won't do that again Commented Jun 9, 2023 at 3:15

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

2 Comments

You should call SetSubComponent(True) only when you are creating a TComponent-derived object in the constructor that needs to appear as a nested property in the Object Inspector. Otherwise, don't call it. That is not the case here.
Yes, I got it. That's why I quoted text from manual in answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.