Skip to content

JFrame's Content Pane

discorddioxin edited this page Mar 31, 2021 · 12 revisions

Content


Why it exists

A window has more than just components you'd want to add to it, such as a label for a title, buttons to minimize and close...

  • Because of this, JFrame designates a JPanel as the content pane for the window - a pane for the application's content.

  • Without understanding content panes, you can experience some strange bugs.


Adding to JFrame.. Or are we?

If we added a JButton to the frame, then printed out all the components the JFrame consists of, you would expect to see a JButton.

However...

JFrame frame = new JFrame();
frame.add(new JButton());

for(Component comp : frame.getComponents())
    System.out.println(comp.getClass().getSimpleName());

The code above prints JRootPane, not JButton. What's going on?

If we dive into frame.add(Component), we will get our answer:

if(isRootPaneCheckingEnabled())
    getContentPane().add(comp, constraints, index);

The documentation for rootPaneCheckingEnabled states:

If true then calls to add and setLayout will be forwarded to the contentPane.

This is initially false, but is set to true when the JFrame is constructed.

So not only is it almost always true, but it affects setLayout too!

If we print the components of the content pane using getContentPane(), we will find the JButton.

for(Component comp : frame.getContentPane().getComponents())
    System.out.println(comp.getClass().getSimpleName());

Fighting over layouts

BoxLayout is a very simple layout.

 BoxLayout layout = new BoxLayout(parent, BoxLayout.X_AXIS);

You specify the parent (component that uses the layout) and specify which axis components should appear on.

So, what happens when we do this?

JFrame frame = new JFrame();
BoxLayout layout = new BoxLayout(frame, BoxLayout.X_AXIS);

frame.setLayout(layout);
frame.add(new JButton());

Shouldn't be an issue, right? Well.. We get an error.

java.awt.AWTError: BoxLayout can't be shared

JFrame "delegated" (passed) the layout to the content pane - the layout was added to the content pane.

However, BoxLayout thinks JFrame is the one using the layout, since we passed it JFrame. But JFrame secretly passed the layout to the content pane, meaning JFrame is not the layout owner.

This causes confusion, resulting in a fail-safe error to prevent visual bugs.

This can be solved by specifying the content pane as the parent for the layout.

JFrame frame = new JFrame();
BoxLayout layout = new BoxLayout(frame.getContentPane(), BoxLayout.X_AXIS);

frame.setLayout(layout);
frame.add(new JButton());

What's the solution?

Only manipulate JFrame if you need to really work with the frame. This includes

  • Setting actions for the X button
  • Setting the title
  • Adding menus
  • Etc..

For everything else, you should use frame.getContentPane() to work with the content pane directly.

Clone this wiki locally