根据评论者的要求进行编辑。我希望这是合规的。

第一篇文章!试图了解为什么我的Swing应用程序不会从一个面板前进到下一个面板。这是代码的一般流程:

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

随着应用程序基于用户输入的进展,MainFrame将填充更多帧(当前,仅对MoviePanel和TownPanel进行编码),并且它们的代码与该代码非常相似-我也粘贴了MoviePanel。

在上面基于KeyAdapter的监听器之后,执行会崩溃。但是,当我在带有断点的Eclipse中以 Debug模式运行应用程序时,这确实可以实现预期的工作,并从MoviePanel前进到TownPanel。因此,我怀疑线程是罪魁祸首。请注意,我确实在上面的代码块上尝试了SwingUtilities.invokeLater()技术的许多不同组合,但没有任何改变。任何帮助,将不胜感激;谢谢!

最佳答案

请执行下列操作:

  • invokeLater用于在GUI事件调度线程
  • 上创建
  • 施工期间不重绘(repaint)
  • set可见的最后

  • 特别是在事件监听器上,再次使用invokeLater来使按钮等具有响应性,然后也对响应进行操作。
    public static void main(String[] args) {
        ...
        SwingUtilities.invokeLater() {
            @Override()
            new Runnable() {
                new MainFrame().setVisible(true);
            }
        };
    }
    

    代码审查

    TitlePanel.TitlePanel中,最好使用绝对布局(即null),而不要在绘画代码中使用setLocation
        setLayout(null);
        newGame = new JButton("New Game");
        continueGame = new JButton("Continue");
        newGame.setBounds(170, 550, 120, 24);
        continueGame.setBounds(605, 550, 120, 24);
    

    ChangeablePanel.close中,还要确保timer.stop()

    MainWindow中使用invokeLater:
    public void gotoNextScreen(ComponentEvent e) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                changeFrame(currentScreen.getNextScreen(), null);
            }
        });
    }
    

    MoviePanel 中,我看不到addKeyListener可以起作用;也许遗漏的代码?还是这可能是您看到的错误?
    此外,我发现一个简单的repaint()可疑;本来期望这样的:
    public void actionPerformed(ActionEvent e) {
        invalidate();
        repaint(10L);
    }
    

    10-08 19:49