views:

641

answers:

3

I have written a custom control, that has several sub panels. I want these sub panels to accept any additional controls dropped on them at design time.

Unfortunately any control that gets dropped at design time ends up on my custom control, not on the panels. This shows in particular if I try to drop a label: The label's blue dots are shown, but it's caption isn't and if I deselect the label, it is no longer visible at all.

simplified code (only one sub panel):

type
  TMyContainer = class(TPanel)
    p_SubPanel: TPanel;
  public
    constructor Create(_Owner: TComponent); override;
  end;

  constructor TMyContainer.Create(_Owner: TComponent);
  begin
    inherited;
    p_SubPanel := TPanel.Create(Self);
    p_SubPanel.Parent := Self;
    p_SubPanel.Align := alClient;
  end;

What am I doing wrong here?

(Just in case it matters: I am using Delphi 2007.)

[edit]

I have now solved it differently. The component no longer contains panels but refers to external panels. This makes it actually much more flexible, but on the downside it is no longer as intuitive to use.

I would still like to know how to accomplish what I described originally. Isn't there an open source component somewhere that does this, so I can study the source code?

+1  A: 

Hi

I cant tell from the details, but are you setting the parent of the label to you sub panel? If its at design time you may need to write code in your main component (eg the container that your panels are in), to figure out which subpanel is accepting the component and set the labels parent property to that subpanel.

I'm pretty sure the a notification method gets called when a component is added or removed from another component, this should help you track down where you need to put the code.

Toby Allen
+1  A: 

This is a good question. You can allow your custom TWinControl to have other controls dropped on it at design-time by adding csAcceptControls to your controls ControlStyle property.

constructor TMyContainer.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csAcceptControls];
end;

But in trying to work this out, I've had little success with being able to drop controls onto a sub panel within a custom control. Adding csAcceptControls to a sub panel's ControlStyle isn't enough. The cloest I've gotten is a hack to convince the sub panel it's being designed like so:

type
  TGiveMeProtected_Component = class(TComponent);

procedure TMyContainer.Create(AOwner: TComponent);
begin
  FSubPanel := TPanel.Create(Self);
  TGiveMeProtected_Component(FSubPanel).SetDesigning(True, True);
end;

Using that code, you can now drop controls onto the sub panel, but it means you can also select the sub panel, change it's properties and even delete it which you definately don't want. Sorry I couldn't come up with the answer, I'd still love to know if you work it out. :)

Ben Daniel
A: 

I did this, but ended up replacing the controls with regular panels which would be shown/hidden when required.

Instead of descending from TPanel my controls descend from TCustomControl. I don't think I could get it to work descending from TPanel but can't remember what the issue was.

The container control:

TPageControl = class(TCustomControl)
private
  PageList:TObjectList;  // To hold references to all sub-pages for easy access.
end;

constructor TPageControl.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csAcceptsControls];
  PageList := TObjectList.Create;
  PageList.OwnsObjects := false;
end;

destructor TVstPageControl.Destroy;
begin
  PageList.Free;
  inherited;
end;

procedure TPageControl.NewPage;
var
  Page:TPage;
begin
  Page := TPage.Create(Self.Owner);
  Page.Parent := Self;
  Page.Align := alClient;

  PageList.Add(Page);
end;

procedure TPageControl.DeletePage(Index:integer);
var
  Page:TPage;
begin
  Page := PageList[Index] as TPage;
  Page.Free;
  PageList.Delete(Index);
end;

The page/sub-panel control:

TVstPage = class(TCustomControl)
public
  constructor Create(AOwner: TComponent); override;
end;

constructor TPage.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csAcceptsControls];
end;
Shannon