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).
I tried two things:
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 ofJFrame
). It worked fine.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
).
So, I do not understand two things.
Why do we have two competing mechanism to do the same things?
What is the reason to use containers in combination with the panels (
JPanel
)? (For example, what for we include buttons in JPanels and then we include JPanels in the Containers). Can we includeJPanel
inJPanel
? 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? I tried just frame.add(panel);
and it works fine.
ADDED 2:
I would like to add some code to be more clear about what I mean. In this example I use only 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). JFrame.getContentPane()
just returns a Container
to place the Component
s that you want to display in the JFrame
. 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.
As for why both JFrame.add()
and JFrame.getContentPane().add()
both do the same thing - JFrame.add()
is overridden to call 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.
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
I believe the reason is because Swing was built off of AWT, and Container is a top level AWT object. It really isn't the greatest design choice, though, since you generally don't want to mix AWT (heavyweight) objects with Swing (lightweight).
I think the best way to handle it is to always cast the contentPane to a JPanel.
JPanel contentPanel = (JPanel)aFrame.getContentPane();
It is all written in the last version API doc that JFrame.add() (nowerdays) is enough.
You may compare to older Java versions here.