Java Basics

ContentPane (or Content Pain?)

JFrames have a content pane, which holds the components. These components are sized and positioned by the layout manager when JFrame's pack() is called.

Content pane border. There are several ways to handle the content pane, but most of them fail to provide one basic requirement -- ability to set a border. If you look at design guidelines (eg, Sun's Java Look and Feel Design Guidelines, Second Edition) and actual practice for attractive windows (both JFrames and JDialogs), you will generally observe the following:

The problem is that the Container class doesn't have a way to set borders.

Inheritance hierarchy

To better understand the situation, it's good to have the inheritance of some of these containers in mind.

JPanel
->
JComponent
setBorder(...)
->
Container
add(...)
setLayout(...)
->
Component
->
Object

Different approaches to using the content pane

You will see all of these approaches used by different programmers. They are all reasonable. Choose the one which makes you most comfortable. They all assume that the code occurs inside of a JFrame subclass constructor or method (ie, this refers to the JFrame).

Create a JPanel. Set the content pane - My favorite.
class GUI extends JFrame {
    . . .
    GUI() {
        . . .
        JPanel content = new JPanel();
        content.setLayout(...);
        content.setBorder(BorderFactory.createEmptyBorder(11,11,11,11));
        content.add(...);
        content.add(...);
        . . .
        setContentPane(content);
Get content pane, work with it. Problem: Unable to set border.
class GUI extends JFrame {
    . . .
    GUI() {
        . . .
        Container content = getContentPane();
        content.setBorder(BorderFactory.createEmptyBorder(11,11,11,11));
        content.setLayout(...);
        content.add(...);
        content.add(...);
        . . .
Use getContentPane for every reference. Problem: Unable to set border.
class GUI extends JFrame {
    . . .
    GUI() {
        . . .
        getContentPane().setLayout(...);
        getContentPane().setBorder(BorderFactory.createEmptyBorder(11,11,11,11));
        getContentPane().add(...);
        getContentPane().add(...);
        . . .
Use Java 5 JFrame pass-through methods. See Blast from the past discussion below.
class GUI extends JFrame {
    . . .
    GUI() {
        . . .
        setLayout(...);
        setBorder(BorderFactory.createEmptyBorder(11,11,11,11));
        add(...);
        add(...);
        . . .

Why I prefer to create a new content pane

Every JFrame comes with a pre-created content pane. What a waste.

Reason: Restrictions on Container. If you try to use the returned Container from getContentPane(), you can't use setBorder(...).

Irony. 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. If we downcast it to JPanel, we create fragile code that might break because the contract with getContentPane() is to return a Container, and there is no guarantee that future versions will actually continue to return a JPanel.

Reason: Generality of one programming style. The overall layout of a window is often created by nesting panels. If you're going to be creating panels and working with them, it's easier to treat them all the same rather than making the top-level content pane a special case.

Reason: What is the default layout? And just what is the default layout for a JFrame's content pane? Is it the same as for an Applet or a newly created JPanel? Surprisingly they aren't the same. And the default was changed in different versions (admittedly you have to go way back to find this change). So I recommend not relying on the default layout. Always explicitly set for the content pane, even if you use the predefined one.

And just in case you thought the default layout was BorderLayout, as the documentation says, you might be surprised that it is really an anonymous inner subclass of BorderLayout. I haven't bothered to look at the source code to figure out why they just didn't use a normal BorderLayout, but it makes me nervous. I hate these FUD (Fear, Uncertainty, Doubt) arguments, but it's what I feel when thinking about the default layouts.

And the final layout issue is that you should be using a better layout than BorderLayout anyway.

Reason to use predefined content pane: efficiency? Creating a JPanel can't be very expensive, but it does cost some execution time. This small one-time cost is worth it.

Blast from the past - Adding directly to a JFrame in Java 5

Long ago, before the Swing GUI library, there was no content pane and components were added directly to the window (the old AWT Frame class).

Swing. When the superior Swing GUI library came along, it was easy, but annoying, to rewrite code to use Swing's content pane. That was long ago, and for most of Java's history programmers have been using the content pane explicitly.

Java 5? For some reason, Java 5 added the ability to use the content pane by creating add() and setLayout() in JFrame which pass-through calls to the underlying content pane so it looks like the old AWT code. Maybe they did this because are request has been on the request queue for a really long time, and it was trivial to implement. Maybe it was just someone's pet project.

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.

Worse than useless. There are lots of ways to make Swing more usable; adding this "feature" seems like a waste of manpower and adds yet more unneeded alternatives. They regularly reject useful additional features because they are concerned about the growing size of the Java API. So...

Raising cognitive complexity with useless options increases every programmer's burden a little bit because they always have to be prepared to deal with this alternative when reading code.

It's your time, waste it if you want to. There is no problem if you want to use this feature, but why get in the habit of using this minimally useful alternative when you have to know how to explicitly deal with a JPanel for many layouts anyway?

Suggested practice: Name the content pane "content"

I suggest giving the content pane JPanel a name that lets the reader know it is the content pane. The name content, which is probably used by more programmers than any other name.