简体   繁体   English

ContentPane和JPanel之间有什么关系?

[英]What is the relation between ContentPane and JPanel?

I found one example in which buttons are added to panels (instances of JPanel ) then panels are added to the the containers (instances generated by getContentPane() ) and then containers are, by the construction, included into the JFrame (the windows). 我找到了一个例子,其中按钮被添加到面板( JPanel实例),然后面板被添加到容器(由getContentPane()生成的实例),然后容器被构造包含在JFrame (窗口)中。

I tried two things: 我尝试了两件事:

  1. I got rid of the containers. 我摆脱了容器。 In more details, I added buttons to a panel (instance of JPanel ) and then I added the panel to the windows (instance of JFrame ). 更详细地说,我向面板( JPanel实例)添加了按钮,然后我将面板添加到了Windows( JFrame实例)。 It worked fine. 它工作正常。

  2. I got rid of the panels. 我摆脱了面板。 In more details, I added buttons directly to the container and then I added the container to the window (instance of JFrame ). 更详细地说,我直接将按钮添加到容器中,然后将容器添加到窗口( JFrame实例)。

So, I do not understand two things. 所以,我不明白两件事。

  1. Why do we have two competing mechanism to do the same things? 为什么我们有两个竞争机制来做同样的事情?

  2. What is the reason to use containers in combination with the panels ( JPanel )? 将容器与面板结合使用( JPanel )的原因是什么? (For example, what for we include buttons in JPanels and then we include JPanels in the Containers). (例如,我们在JPanels中包含按钮,然后在Containers中包含JPanels)。 Can we include JPanel in JPanel ? 我们可以包括JPanelJPanel Can we include a container in container? 我们可以在容器中包含容器吗?

ADDED: 添加:

Maybe essence of my question can be put into one line of code: 也许我的问题的本质可以放在一行代码中:

frame.getContentPane().add(panel);

What for we put getContentPane() in between? 我们把getContentPane()置于什么之间? I tried just frame.add(panel); 我试过了frame.add(panel); and it works fine. 它工作正常。

ADDED 2: 增加2:

I would like to add some code to be more clear about what I mean. 我想添加一些代码来更清楚我的意思。 In this example I use only JPane: 在这个例子中我只使用JPane:

import java.awt.*;
import javax.swing.*;
public class HelloWorldSwing {
    public static void main(String[] args) {
        JFrame frame = new JFrame("HelloWorldSwing");
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());        
        panel.add(new JButton("W"), BorderLayout.NORTH);
        panel.add(new JButton("E"), BorderLayout.SOUTH);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

And in this example I use only Content Pane: 在这个例子中,我只使用内容窗格:

import java.awt.*;
import javax.swing.*;
public class HelloWorldSwing {
    public static void main(String[] args) {
    JFrame frame = new JFrame("HelloWorldSwing");
    Container pane = frame.getContentPane();
    pane.setLayout(new BorderLayout()); 
    pane.add(new JButton("W"), BorderLayout.NORTH);
    pane.add(new JButton("E"), BorderLayout.SOUTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
    }
}

Both work fine! 两者都很好! I just want to know if between these two ways to do things one is better (safer). 我只是想知道在这两种方法之间做一件事是否更好(更安全)。

It's not two competing mechanisms - a JPanel is a Container (just look at the class hierarchy at the top of the JPanel javadocs ). 这不是两个竞争机制 - JPanel 是一个 Container (只需查看JPanel javadocs顶部的类层次结构)。 JFrame.getContentPane() just returns a Container to place the Component s that you want to display in the JFrame . JFrame.getContentPane()只返回一个Container来放置要在JFrame显示的Component Internally, it's using a JPanel (by default - you can change this by calling setContentPane() ) As for why it's returning a Container instead of a JPanel - it's because you should program to an interface, not an implementation - at that level, all that you need to care about is that you can add Component s to something - and even though Container is a class rather than an interface - it provides the interface needed to do exactly that. 在内部,它使用JPanel (默认情况下 - 你可以通过调用setContentPane()来改变它)至于为什么它返回一个Container而不是JPanel - 这是因为你应该编程到一个接口,而不是一个实现 - 在那个级别,所有您需要关心的是,您可以将Component添加到某个东西 - 即使Container是一个类而不是一个接口 - 它提供了完成该操作所需的接口。

As for why both JFrame.add() and JFrame.getContentPane().add() both do the same thing - JFrame.add() is overridden to call JFrame.getContentPane().add() . 至于为什么都JFrame.add()JFrame.getContentPane().add()都做同样的事情- JFrame.add()是重写调用JFrame.getContentPane().add() This wasn't always the case - pre-JDK 1.5 you always had to specify JFrame.getContentPane().add() explicitly and JFrame.add() threw a RuntimeException if you called it, but due to many complaints, this was changed in JDK 1.5 to do what you'd expect. 情况并非总是如此 - 在JDK 1.5之前,你总是必须明确指定JFrame.getContentPane().add() ,如果你调用它, JFrame.add()抛出一个RuntimeException ,但是由于很多抱怨,这个被改变了在JDK 1.5中做你期望的事情。

Good question. 好问题。 I found it helpful to understand that "Swing provides three generally useful top-level container classes: JFrame , JDialog , and JApplet . ... As a convenience, the add method and its variants, remove and setLayout have been overridden to forward to the contentPane as necessary."— Using Top-Level Containers 我发现有助于理解“Swing提供了三个通常有用的顶级容器类: JFrameJDialogJApplet ....为方便起见,add方法及其变体,remove和setLayout已被覆盖以转发到必要时使用 contentPane。“ - 使用顶级容器

I believe the reason is because Swing was built off of AWT, and Container is a top level AWT object. 我相信原因是因为Swing是由AWT构建的,而Container是一个顶级的AWT对象。 It really isn't the greatest design choice, though, since you generally don't want to mix AWT (heavyweight) objects with Swing (lightweight). 但是,它确实不是最好的设计选择,因为您通常不希望将AWT(重量级)对象与Swing(轻量级)混合使用。

I think the best way to handle it is to always cast the contentPane to a JPanel. 我认为处理它的最佳方法是始终将contentPane强制转换为JPanel。

JPanel contentPanel = (JPanel)aFrame.getContentPane();

It is all written in the last version API doc that JFrame.add() (nowerdays) is enough. 它全部写在最后一个版本的API文档中 ,JFrame.add()(nowerdays)就足够了。

You may compare to older Java versions here . 您可以在此处与较旧的Java版本进行比较。

有趣的是: jframe.setBackground(color)对我不起作用,但jframe.getContentPane().setBackground(color)有效。

The history and mechanics of this are also discussed in some detail at this leepoint article . 这篇leepoint文章中也详细讨论了它的历史和机制。 Note in particular: 特别注意:

getContentPane() returns a Container object. getContentPane()返回一个Container对象。 This isn't really a plain Container object, but is actually a JPanel ! 这不是一个普通的Container对象,但实际上是一个JPanel This is a Container as a consequence of the hierarchy. 作为层次结构的结果,这是一个Container So if we get the predefined content pane, it turns out it's actually a JPanel , but we really can't take advantage of the functionality that was added by JComponent . 因此,如果我们获得预定义的内容窗格,事实证明它实际上是一个JPanel ,但我们实际上无法利用JComponent添加的功能。

and

They defined add() methods in JFrame which simply call the corresponding add() methods for the content pane. 他们在JFrame定义了add()方法,它只是为内容窗格调用相应的add()方法。 It seems strange to add this feature now, especially since many layouts use multiple nested panels so you still have to be comfortable with adding directly to a JPanel . 现在添加此功能似乎很奇怪,特别是因为许多布局使用多个嵌套面板,因此您仍然必须习惯于直接添加到JPanel And not everything you want to do with the content pane can be done through calls to the JFrame . 并非您想要对内容窗格执行的所有操作都可以通过调用JFrame来完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM