开发者

How to detach a panel and show it in a separate window?

Let's say I have form A that contains a panel (with many other controls in it) and a form B that it is empty.

Can I programmatically detach the panel from form A and move it in form B (and maybe back to form A)?

I know that I can change the Owner of the panel but do开发者_如何学Ces it work between different forms?

Update:

After some Googling I see that there is a ParentWindow property.


As noted by others, there are several problems with changing the parent window of a control without changing the ownership, and changing a controls owner can be difficult if it has multiple controls sitting on it...

One way around it is to use a frame instead. A frame owns all of it's sub-controls, so all you would need to do is change the owner and parent of the frame, and everything else will come along with it. This approach also allows you to keep all the event handlers and glue code in a single place as well.

N@


You have to take ownership into account, otherwise the destruction of form A would lead to the disappearance (i.e. destruction) of your panel on form B, or worse.

type
  TForm2 = class(TForm)
  public
    InsertedPanel: TControl;  // or TPanel 

.

procedure RemoveComponents(AForm: TComponent; AControl: TWinControl);
var
  I: Integer;
begin
  for I := 0 to AControl.ControlCount - 1 do
  begin
    if AControl.Controls[I] is TWinControl then
      RemoveComponents(AForm, TWinControl(AControl.Controls[I]));
    if AControl.Controls[I].Owner = AForm then
      AForm.RemoveComponent(AControl.Controls[I]);
  end;
  AForm.RemoveComponent(AControl);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  Form2.InsertedPanel := Panel1;
  Panel1.Parent := nil;
  RemoveComponents(Self, Panel1);
  Form2.InsertComponent(Form2.InsertedPanel); // < this is not necessary
  Form2.InsertedPanel.Parent := Form2;        //   as long as Parent is set
  Panel1 := nil;                              //   or if you free the panel
end;                                          //   manually

The extra reference may seem a bit silly: Form2.InsertedPanel and Panel1 point to the same object, but it's kind of semantically preferred. Maybe a central controlled variable is better.

Update:

I falsely assumed that RemoveComponent cascaded to the child controls on the panel. It doesn't, of course, so only removing the panel from form A would leave all the child controls of the panel still owned by form A. So I added the RemoveComponents routine to remove ownership from all the child controls of the panel.

Note that the child controls of the panel don't have an owner at this time. But since they are parented controls of the panel, destruction of the panel will free those controls. So be sure the panel has a parent, or free the panel explicitly.

All of the above only applies to a design time created panel, placed design time on the form, which was my assumption. Since this changing parents behaviour is apparently wanted or needed, you might want to consider to implement it completely at runtime. To keep the abbility to design the panel designtime, I suggest to create a Frame on which you can design that panel, and jump the Frame around your forms.


You can easily have something appear as if it was a panel, and also as a form, by really using a TForm for what you would have used the panel for. Then dock the form at runtime into the place where you have a blank panel left for that purpose, and undock it at runtime, by the same manner.

You can't undock a TPanel and have it appear as a top-level form window, but you can take a top level form window and dock it in code. To get the appearance and functionality you want you must use the correct tools (TForm, in this case).

Incidentally, component libraries like Toolbar 2000 do allow floating toolbar windows based on toolbar panels, so if you really insist on having all the designtim elements remain in one form, at desigtime, you should look into how it works in Toolbar 2000. It has a lot of code in there to render the toolbar in "undocked/floating" mode, and to handle the mouse-driven docking and undocking of toolbars into toolbar docks.


If the panel and child components are created at runtime, you can just set the Parent of the Panel to FormB:

Panel1.Parent := FormB;

Note that FormB has to have been created already before you can do this.

For more info, see the Delphi Wiki page here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜