我发现了一个示例,其中将按钮添加到面板(JPanel的实例),然后将面板添加到容器(getContentPane()生成的实例),然后根据构造将容器包括在JFrame中(窗户)。
我尝试了两件事:
我摆脱了容器。在更多详细信息中,我将按钮添加到面板(JPanel的实例),然后将面板添加到窗口(JFrame的实例)。工作正常。
我摆脱了面板。更详细地讲,我将按钮直接添加到容器中,然后将容器添加到窗口中(JFrame的实例)。
所以,我不明白两件事。
为什么我们有两种竞争机制来做相同的事情?
将容器与面板(JPanel)结合使用的原因是什么? (例如,为此我们在JPanels中包含按钮,然后在Containers中包含JPanels)。我们可以在JPanel中包含JPanel吗?我们可以在容器中包括一个容器吗?
添加:
也许我的问题的实质可以放在一行代码中:
frame.getContentPane().add(panel);
我们将getContentPane()放在中间是什么呢?我只尝试了frame.add(panel);,它工作正常。
添加2:
我想添加一些代码以更清楚地了解我的意思。在此示例中,我仅使用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);
}
}
在此示例中,我仅使用内容窗格:
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);
}
}
两者都很好!我只想知道这两种做事方式之间是否更好(更安全)。
它不是两个相互竞争的机制-JPanel是Container(只需查看JPanel javadocs顶部的类层次结构)。 JFrame.getContentPane()只是返回一个Container将要显示的Component放置在JFrame中。在内部,它使用JPanel(默认情况下-您可以通过调用setContentPane()进行更改)至于为什么它返回Container而不是JPanel的原因-这是因为您应该对接口进行编程,而不是对实现进行编程-在该级别上,您需要关心的就是可以将Component添加到某些内容中-即使Container是类而不是接口,它也提供了实现此目的所需的接口。
至于为什么JFrame.add()和JFrame.getContentPane().add()都做同样的事情-JFrame.add()被覆盖以调用JFrame.getContentPane().add()。并非总是这样-在JDK 1.5之前,您始终必须明确指定JFrame.getContentPane().add(),而JFrame.add()则抛出一个RuntimeException,但是由于许多投诉,JDK 1.5中对此进行了更改以执行以下操作您会期望的。
@Nate,"内部使用JPanel"是什么意思。您的意思是Container正在使用JPanel?你是什??么意思?我虽然说JPanel是Container的子类。我可以通过" setContentPane"更改什么?好。您说Container是一个类(我一直认为Container是一个类)。但是JPane也是一个类。为什么我们不能仅使用JPane或仅使用Container?我仅使用JPane就能做同样的事情。我还可以只使用容器来完成相同的操作。
JFrame在内部使用JPanel对象支持getContentPane()方法。这就是Zacharys答案有效的原因。实际的JPanel引用埋在JFrame.rootPane字段中。您可以在JFrame上调用setContentPane()-例如,您可以将第一个示例中的第10行从frame.add(panel)更改为frame.setContentPane(panel)。 Container是一个类。 JPanel是一个类(它是Container的子类)。您将引用的类型与引用所引用的对象的类型混淆了。考虑Container container = new JPanel()
@Nate源(pragmaticjava.blogspot.com.ar/2008/08/)已删除。
@Lucio谢谢!将链接更改为此处关于StackOverflow的关于同一件事的问题。
好问题。我发现了解以下内容很有帮助:" Swing提供了三个通常有用的顶级容器类:JFrame,JDialog和JApplet。...为方便起见,add方法及其变体,remove和setLayout具有已被覆盖以根据需要转发到contentPane。" —使用顶级容器
在此leepoint文章中还对此进行了详细讨论。特别注意:
getContentPane() returns a Container object. This isn't really a plain Container object, but is actually a JPanel! This is a Container as a consequence of the hierarchy. 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.
和
They defined add() methods in JFrame which simply call the corresponding add() methods for the content pane. 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. And not everything you want to do with the content pane can be done through calls to the JFrame.
有趣:jframe.setBackground(color)对我不起作用,但是jframe.getContentPane().setBackground(color)有效。
JFrame.add()(如今)已足够用最新版本的API文档编写。
您可以在此处与旧Java版本进行比较。
我相信原因是因为Swing是基于AWT构建的,而Container是顶级AWT对象。但是,这实际上并不是最佳的设计选择,因为您通常不希望将AWT(重量级)对象与Swing(轻量级)对象混合使用。
我认为最好的处理方法是始终将contentPane投射到JPanel。
JPanel contentPanel = (JPanel)aFrame.getContentPane();
它没有混合AWT和Swing组件...请参阅我的回答