【问题标题】:Swapping JPanel, 2nd JPanel doesn't display交换 JPanel,第二个 JPanel 不显示
【发布时间】:2015-04-02 19:59:05
【问题描述】:

我有一个 JFrame 和 2 个 JPanel。一个面板是带有按钮的开始屏幕。另一个面板是游戏画面。当我删除开始屏幕并显示游戏屏幕时,JFrame 没有任何反应。开始屏幕是持久的但不可用,游戏在后台运行而不更新屏幕。游戏结束后,开始画面再次可用。我在网上到处搜索解决方案。他们都说 removeAll、revalidate、repaint、pack 或 getContentPane.removeAll。我无法让这些解决方案中的任何一个起作用。这是驱动程序类:

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);
            }
        });
    }       
}

编辑: 我已经更新了类以使用卡片布局,但同样的事情发生了。

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 的案例
  • CardLayout 效果很好。问题是我在同一个线程上更新 JPanel。我需要线程一个新线程来运行游戏。

标签: java dynamic jframe jpanel swap


【解决方案1】:

CardLayout 允许您将多个面板添加到Container,一次仅显示一个面板,并且能够在面板之间切换。您将父级的布局设置为CardLayout,将面板添加到您的框架,指定名称作为约束:

 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");

添加的第一个面板是第一个显示的 tk。要在面板之间切换,请调用CardLayout#show(Container, String),传入面板的父级(视为“deck”)和您想要的特定面板的名称(视为“卡片 em>")。

 layout.show(frame, "second");

CardLayout 的一个常见问题是将父级调整为当前面板的大小。这可以通过extending upon CardLayout实现

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    • 2014-01-16
    • 1970-01-01
    相关资源
    最近更新 更多