How do I change JPanel inside a JFrame on the fly?

Viewed 160872

To put it simple, there's a simple java swing app that consists of JFrame with some components in it. One of the components is a JPanel that is meant to be replaced by another JPanel on user action.

So, what's the correct way of doing such a thing? I've tried

panel = new CustomJPanelWithComponentsOnIt();
parentFrameJPanelBelongsTo.pack();

but this won't work. What would you suggest?

14 Answers

Your use case, seems perfect for CardLayout.

In card layout you can add multiple panels in the same place, but then show or hide, one panel at a time.

1) Setting the first Panel:

JFrame frame=new JFrame();
frame.getContentPane().add(new JPanel());

2)Replacing the panel:

frame.getContentPane().removeAll();
frame.getContentPane().add(new JPanel());

Also notice that you must do this in the Event's Thread, to ensure this use the SwingUtilities.invokeLater or the SwingWorker

frame.setContentPane(newContents());
frame.revalidate(); // frame.pack() if you want to resize.

Remember, Java use 'copy reference by value' argument passing. So changing a variable wont change copies of the reference passed to other methods.

Also note JFrame is very confusing in the name of usability. Adding a component or setting a layout (usually) performs the operation on the content pane. Oddly enough, getting the layout really does give you the frame's layout manager.

Hope this piece of code give you an idea of changing jPanels inside a JFrame.

public class PanelTest extends JFrame {

        Container contentPane;

        public PanelTest()  {
           super("Changing JPanel inside a JFrame");
           contentPane=getContentPane();
        }

        public void createChangePanel() {
           contentPane.removeAll();
           JPanel newPanel=new JPanel();
           contentPane.add(newPanel);
           System.out.println("new panel created");//for debugging purposes
           validate();
           setVisible(true);
        }
}

On the user action:

// you have to do something along the lines of

myJFrame.getContentPane().removeAll()
myJFrame.getContentPane().invalidate()

myJFrame.getContentPane().add(newContentPanel)
myJFrame.getContentPane().revalidate()

Then you can resize your wndow as needed.

Game game =  new Game();
getContentPane().removeAll(); 
setContentPane(game);  
getContentPane().revalidate(); //IMPORTANT
getContentPane().repaint();    //IMPORTANT

It all depends on how its going to be used. If you will want to switch back and forth between these two panels then use a CardLayout. If you are only switching from the first to the second once and (and not going back) then I would use telcontars suggestion and just replace it. Though if the JPanel isn't the only thing in your frame I would use remove(java.awt.Component) instead of removeAll.

If you are somewhere in between these two cases its basically a time-space tradeoff. The CardLayout will save you time but take up more memory by having to keep this whole other panel in memory at all times. But if you just replace the panel when needed and construct it on demand, you don't have to keep that meory around but it takes more time to switch.

Also you can try a JTabbedPane to use tabs instead (its even easier than CardLayout because it handles the showing/hiding automitically)

The other individuals answered the question. I want to suggest you use a JTabbedPane instead of replacing content. As a general rule, it is bad to have visual elements of your application disappear or be replaced by other content. Certainly there are exceptions to every rule, and only you and your user community can decide the best approach.

I suggest you to add both panel at frame creation, then change the visible panel by calling setVisible(true/false) on both. When calling setVisible, the parent will be notified and asked to repaint itself.

Related