I have a JFrame and 2 JPanels. One panel is the start screen with buttons. The other panel is the game screen. When I remove the start screen and display the game screen nothing happens to the JFrame. The start screen is persistent but not usable and the game runs in the background without updating the screen. When the game completes the start screen is usable again. I've searched everywhere online for a solution. They all say removeAll, revalidate, repaint, pack, or getContentPane.removeAll. I've not been able to get any of these solutions to work. Here is the driver class:
public class BallDriver extends JFrame {
private static final long serialVersionUID = 1L;
int width = 500;
int height = 500;
Container cont;
StartScreen start;
BallGame ballGame;
public BallDriver() {
cont = getContentPane();
startScreen();
}
private void startScreen() {
setTitle("BallGame");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(new Dimension(width, height));
setPreferredSize(new Dimension(500,500));
start = new StartScreen();
JButton[] startButtons = start.getButtons();
setupButtons(startButtons);
add(start, BorderLayout.CENTER);
}
private void startGame(String difficulty) throws InterruptedException {
removeAll();
setSize(new Dimension(width, height));
setPreferredSize(new Dimension(width, height));
ballGame = new BallGame(width, height);
ballGame.setPreferredSize(new Dimension(width, height));
add(ballGame, BorderLayout.CENTER);
revalidate();
repaint();
while(!ballGame.endGame()) {
ballGame.moveBall();
ballGame.repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) { e.printStackTrace(); }
}
removeAll();
add(start, BorderLayout.CENTER);
revalidate();
repaint();
}
private void setupButtons(final JButton[] buttons) {
for (JButton button : buttons) {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Object object = e.getSource();
try {
if (object == buttons[0])
startGame(StartScreen.MODE_EASY);
if (object == buttons[1])
startGame(StartScreen.MODE_NORMAL);
if (object == buttons[2])
startGame(StartScreen.MODE_HARD);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
});
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
BallDriver ballDriver = new BallDriver();
ballDriver.setVisible(true);
}
});
}
}
EDIT: I've updated the class to use cardlayout, but the same thing occurs.
public class BallDriver extends JFrame {
private static final long serialVersionUID = 1L;
int width = 500;
int height = 500;
JPanel cardPanel = new JPanel();
Container cont;
StartScreen start;
BallGame ballGame;
CardLayout cardLayout = new CardLayout();
public BallDriver() {
setTitle("BallGame");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(new Dimension(width, height));
setPreferredSize(new Dimension(width, height));
cardPanel.setLayout(cardLayout);
cont = getContentPane();
add(cardPanel, BorderLayout.CENTER);
startScreen();
}
private void startScreen() {
start = new StartScreen();
JButton[] startButtons = start.getButtons();
setupButtons(startButtons);
cardPanel.add(start, "start");
cardLayout.show(cardPanel, "start");
}
private void startGame(String difficulty) throws InterruptedException {
ballGame = new BallGame(width, height);
cardPanel.add(ballGame, "game");
cardLayout.show(cardPanel, "game");
cardPanel.revalidate();
cardPanel.repaint();
while(!ballGame.endGame()) {
System.out.println("Running");
ballGame.moveBall();
ballGame.repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) { e.printStackTrace(); }
}
}
private void setupButtons(final JButton[] buttons) {
for (JButton button : buttons) {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Object object = e.getSource();
try {
if (object == buttons[0])
startGame(StartScreen.MODE_EASY);
if (object == buttons[1])
startGame(StartScreen.MODE_NORMAL);
if (object == buttons[2])
startGame(StartScreen.MODE_HARD);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
});
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
BallDriver ballDriver = new BallDriver();
ballDriver.setVisible(true);
}
});
}
}
CardLayout
allows you to add multiple panels to a Container
, displaying only 1 panel at a time, with the ability to switch between panels. You set the parent's layout to CardLayout
, add panels to your frame specifying a name as the constraints:
CardLayout layout = new CardLayout();
JFrame frame = new JFrame();
frame.setLayout(layout);
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
frame.add(panel1, "first");
frame.add(panel2, "second");
The first panel added is the first tk be displayed. To switch between panels, call CardLayout#show(Container, String)
, passing in the parent of the panels (considered the "deck") and the name of the specific panel you want (considered the "card").
layout.show(frame, "second");
A common problem people have with CardLayout
is having the parent resize to the current panel's size. This can be achieved by extending upon CardLayout