Edited at the request of commenters. I hope this is compliant.
First post! Trying to understand why my Swing application will not advance from one panel to the next. Here is the general flow of the code :
public class MainWindow {
JFrame mainFrame;
ChangeablePanel currentScreen; // abstract and extends JPanel, has getters &
setters for a Timer (swing timer), a String (nextScreen), and an Image
(background image). also has a close(AWTEvent e) method that simply calls
"this.setVisible(false);"
public MainWindow() {
mainFrame = new JFrame("New Arcana");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitleFrame();
} // MainFrame constructor
public void changeFrame(String frameType, String frameName) {
switch (frameType) {
case "Title":
setTitleFrame();
break;
case "Town":
setTownFrame(frameName);
break;
case "Movie":
setMovieFrame(frameName);
break;
default:
break;
} // switch
} // changeFrame
private void setTitleFrame() {
currentScreen = new TitlePanel();
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
} // setTitleFrame
private void setTownFrame(String townName) {
currentScreen = new TownPanel(townName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(townScreenLength, townScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setTownFrame
private void setMovieFrame(String movieName) {
currentScreen = new MoviePanel(movieName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setMovieFrame
private class ScreenChangeListener implements ComponentListener {
@Override
public void componentHidden(ComponentEvent e) {
gotoNextScreen(e);
}
public void componentMoved(ComponentEvent e) {}
public void componentResized(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
} // ScreenChangeListener
public void gotoNextScreen(ComponentEvent e) {
changeFrame(currentScreen.getNextScreen(), null);
}
} // MainWindow
public class Start {
...
public static void main(String[] args) {
initialize();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainWindow();
}
});
} // main
...
} // Start
public class TitlePanel extends ChangeablePanel implements ActionListener {
JButton newGame, continueGame;
public TitlePanel() {
setFocusable(true);
...
newGame = new JButton("New Game");
continueGame = new JButton("Continue");
newGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setNextScreen("Movie");
close(e);
}
});
add(newGame);
add(continueGame);
createTimer(10, this);
getTimer().start();
} // TitlePanel constructor
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawTitleScreen(g2d);
} // paintComponent
private void drawTitleScreen(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
newGame.setLocation(170, 550);
continueGame.setLocation(605, 550);
} // drawTitleScreen
} // TitlePanel
public class MoviePanel extends ChangeablePanel implements ActionListener {
public MoviePanel(String movieName) {
setFocusable(true);
addKeyListener(new AnyKeyActionListener());
...
createTimer(10, this);
getTimer().start();
} // TitlePanel constructor
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
drawMovie(g2d);
} // paintComponent
private void drawMovie(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
} // drawTitleScreen
private class AnyKeyActionListener extends KeyAdapter {
public void keyTyped(KeyEvent e) {
setNextScreen("Town");
close(e);
} // keyPressed
} // listener to check for keystrokes
} // MoviePanel
The MainFrame is to be populated with more frames as the application advances based on user-input (currently, only MoviePanel and TownPanel are coded), and their code is fairly analogous to this one — I pasted MoviePanel as well.
Execution breaks down after the KeyAdapter-based listener above. However, when I run my application in Debug mode in Eclipse with breakpoints, this indeed does what it’s supposed to do and advances from the MoviePanel to the TownPanel. It is because of this that I suspect threading is the culprit here. Note that I did try many different combinations of the SwingUtilities.invokeLater() technique on the code-blocks above, but it didn’t change anything. Any help would be appreciated; thanks!
Do the following:
Especially on event listeners again use invokeLater, to let buttons and such be responsive, and have then actions being taken with response too.
Code review
In
TitlePanel.TitlePanelbetter use an absolute layout (that means null), instead of usingsetLocationin the painting code.In
ChangeablePanel.closeensure alsotimer.stop().In
MainWindowuseinvokeLater:In
MoviePanelI cannot see thataddKeyListenercould function; maybe the left-out code? Or is this maybe the error you saw?Furthermore I find a simple
repaint()dubious; would have expected something like: