ContentPane 和 JPanel 有啥关系?

Posted

技术标签:

【中文标题】ContentPane 和 JPanel 有啥关系?【英文标题】:What is the relation between ContentPane and JPanel?ContentPane 和 JPanel 有什么关系? 【发布时间】:2011-01-26 19:58:07 【问题描述】:

我发现了一个示例,其中按钮被添加到面板(JPanel 的实例),然后面板被添加到容器(由getContentPane() 生成的实例),然后容器通过构造包含到 @ 987654323@(窗户)。

我尝试了两件事:

    我摆脱了容器。更详细地说,我将按钮添加到面板(JPanel 的实例),然后将面板添加到窗口(@98​​7654325@ 的实例)。效果很好。

    我摆脱了面板。更详细地说,我直接将按钮添加到容器中,然后将容器添加到窗口中(JFrame 的实例)。

所以,我不明白两件事。

    为什么我们有两种竞争机制来做同样的事情?

    将容器与面板结合使用的原因是什么 (JPanel)? (例如,我们在 JPanel 中包含按钮,然后在容器中包含 JPanel)。我们可以在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);
    

两者都工作正常!我只是想知道这两种做事方式之间是否有一种更好(更安全)。

【问题讨论】:

【参考方案1】:

这不是两个相互竞争的机制 - JPanel Container(只需查看JPanel javadocs 顶部的类层次结构)。 JFrame.getContentPane() 只返回一个Container 以将您要显示的Components 放置在JFrame 中。在内部,它使用JPanel(默认情况下-您可以通过调用setContentPane()来更改它)至于为什么它返回Container而不是JPanel-这是因为您应该program to an interface, not an implementation-在那个级别,您需要关心的只是您可以将Components 添加到某个东西上——即使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() 方法。这就是 Zachary 的回答有效的原因。实际的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 谢谢!将链接更改为 *** 上关于同一件事的问题。【参考方案2】:

this leepoint article 也详细讨论了这方面的历史和机制。特别注意:

getContentPane() 返回一个Container 对象。这实际上不是一个普通的Container 对象,但实际上是一个JPanel!这是一个Container 作为层次结构的结果。所以如果我们得到预定义的内容窗格,它实际上是一个JPanel,但我们真的无法利用JComponent 添加的功能。

他们在JFrame 中定义了add() 方法,这些方法只是为内容窗格调用相应的add() 方法。现在添加此功能似乎很奇怪,特别是因为许多布局使用多个嵌套面板,因此您仍然必须对直接添加到 JPanel 感到满意。并非您想要对内容窗格执行的所有操作都可以通过调用JFrame 来完成。

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

好问题。我发现理解“Swing 提供了三个通常有用的***容器类:JFrameJDialogJApplet.... 为方便起见,add 方法及其变体、remove 和 setLayout 具有被覆盖以根据需要转发到 contentPane。"—Using Top-Level Containers

【讨论】:

【参考方案5】:

上个版本API doc写的都是JFrame.add()(现在)就够了。

您可以与较旧的 Java 版本进行比较 here。

【讨论】:

【参考方案6】:

我相信原因是因为 Swing 是基于 AWT 构建的,而 Container 是*** AWT 对象。不过,这确实不是最好的设计选择,因为您通常不希望将 AWT(重量级)对象与 Swing(轻量级)混合。

我认为处理它的最佳方法是始终将 contentPane 转换为 JPanel。

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

【讨论】:

它没有混合 AWT 和 Swing 组件...看我的回答

以上是关于ContentPane 和 JPanel 有啥关系?的主要内容,如果未能解决你的问题,请参考以下文章

在主窗口中切换 JPanel

JPanel与JFrame有啥关系 与不同的

框架中间的JPanel

似乎在 FocusListener 中没有读取 JPanel 背景

Swing的布局方式

Java 每次把一个Swing组件放在一个JPanel中时,总是放在左边,有啥办法让其放在面板中间?