如何分离面板并将其显示在单独的窗口中?

发布于 2024-11-17 10:30:43 字数 186 浏览 3 评论 0原文

假设我有一个包含面板(其中有许多其他控件)的表单 A 和一个空的表单 B。
我可以通过编程方式将面板与表单 A 分离并将其移动到表单 B 中(也可能返回到表单 A)吗?

我知道我可以更改面板的所有者,但是它可以在不同的表单之间工作吗?

更新:
经过一番谷歌搜索后,我发现有一个 ParentWindow 属性。

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 does it work between different forms?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

生生不灭 2024-11-24 10:30:43

正如其他人所指出的,在不更改所有权的情况下更改控件的父窗口存在几个问题,并且如果控件上有多个控件,则更改控件所有者可能会很困难......

解决这个问题的一种方法是使用框架反而。框架拥有它的所有子控件,因此您需要做的就是更改框架的所有者和父级,其他所有内容都会随之而来。这种方法还允许您将所有事件处理程序和粘合代码保留在一个位置。

氮@

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@

孤君无依 2024-11-24 10:30:43

通过真正使用 TForm 来实现面板的用途,您可以轻松地让某些东西看起来像面板,也可以作为表单。然后在运行时将窗体停靠到为此目的留有空白面板的位置,并以相同的方式在运行时取消停靠它。

您无法取消停靠 TPanel 并将其显示为顶级表单窗口,但您可以获取顶级表单窗口并将其停靠在代码中。要获得您想要的外观和功能,您必须使用正确的工具(在本例中为 TForm)。

顺便说一句,像 Toolbar 2000 这样的组件库确实允许基于工具栏面板的浮动工具栏窗口,因此,如果您确实坚持让所有 designtim 元素在设计时保持一种形式,您应该研究一下它在 Toolbar 2000 中的工作原理。其中有很多代码用于以“取消停靠/浮动”模式呈现工具栏,并处理鼠标驱动的工具栏停靠和从工具栏停靠中取消停靠。

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.

傾旎 2024-11-24 10:30:43

您必须考虑所有权,否则表格 A 的破坏将导致表格 B 上的面板消失(即破坏),或更糟。

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

额外的引用可能看起来有点愚蠢:Form2.InsertedPanelPanel1 指向同一个对象,但它在语义上是首选。也许中央控制变量更好。

更新:

我错误地认为RemoveComponent级联到面板上的子控件。当然,事实并非如此,因此只有从窗体 A 中删除面板才会使面板的所有子控件仍归窗体 A 所有。因此,我添加了 RemoveComponents 例程以删除面板的所有子控件的所有权。

请注意,此时面板的子控件没有所有者。但由于它们是面板的父控件,因此销毁面板将释放这些控件。因此,请确保该面板有一个父面板,或者显式释放该面板。

以上所有内容仅适用于设计时创建的面板,将设计时放置在表单上,​​这是我的假设。由于这种改变父母行为显然是想要或需要的,因此您可能需要考虑在运行时完全实现它。为了保持设计面板的能力,我建议创建一个框架,您可以在其上设计该面板,并在表单周围跳转该框架。

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.

她说她爱他 2024-11-24 10:30:43

如果面板和子组件是在运行时创建的,则只需将面板的 Parent 设置为 FormB

Panel1.Parent := FormB;

请注意,FormB 必须具有在您执行此操作之前已经创建了。

有关详细信息,请参阅此处的 Delphi Wiki 页面。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文