【问题标题】:CardLayout in simple Game doesn't switch the JPanel properly简单游戏中的 CardLayout 无法正确切换 JPanel
【发布时间】:2017-04-23 11:28:00
【问题描述】:

我正在为我的学习制作游戏“Breakout”的重新制作版本,但遇到了一个奇怪的问题:

我有一个简单的开始屏幕,玩家应该能够在其中输入名称并查看当前的高分等。要开始游戏,我使用 CardLayout 应该切换到gamePanel。不知何故,这不会发生,但游戏循环开始了,当球离开 JPanel 时,我收到 game Over 消息。奇怪的是,gamePanel 与 Over JOptionPane 游戏一起出现,并且切换回开始屏幕正常工作。我也在 StackOverflow 上进行了很多搜索,但我找到的解决方案都没有为我工作。这是我的代码:

这是我的Game.java,main Method所在的地方:

public class Game  extends JFrame {
    private static final int width = 1280;
    private static final int height = 720;
    private static final String LOBBY_PANEL = "Lobby Panel";
    private static final String GAME_PANEL = "Game Panel";
    private boolean run = false;
    private CardLayout cardLayout;
    private JPanel cardPanel = new JPanel();
    private LobbyPanel lobbyPanel;
    private GamePanel gamePanel;

    public Game(){
        super("Breakout Remastered");
        cardPanel.setLayout(new CardLayout());
        cardLayout = (CardLayout) cardPanel.getLayout();
        lobbyPanel = new LobbyPanel(this);
        gamePanel = new GamePanel(this);
        cardPanel.add(lobbyPanel, LOBBY_PANEL);
        cardPanel.add(gamePanel, GAME_PANEL);
        this.add(cardPanel);
        this.pack();
        this.setSize(width, height);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        cardLayout.show(cardPanel, LOBBY_PANEL);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Game gameFrame = new Game();
            gameFrame.setVisible(true);
        });

    }

    public void playGame() {
        cardLayout.show(cardPanel, GAME_PANEL);
        this.validate();
        this.repaint();
        this.run = true;

        while (run) {
            gamePanel.move();
            gamePanel.repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException iEx) {
                iEx.printStackTrace();
            }
        }
    }

    public void stopGame() {
        cardLayout.show(cardPanel, LOBBY_PANEL);
        this.run = false;
    }
}

这是我的 GamePanel.java:

public class GamePanel extends JPanel {
    private Game game;
    private Ball ball = new Ball(this);
    private Racquet racquet = new Racquet(this);

    public GamePanel(Game game) {
        this.game = game;
        KeyListener keyListener = new KeyListener() {
            @Override
            public void keyTyped(KeyEvent keyEvent) {

            }

            @Override
            public void keyPressed(KeyEvent keyEvent) {
                racquet.keyPressed(keyEvent);
            }

            @Override
            public void keyReleased(KeyEvent keyEvent) {
                racquet.keyReleased(keyEvent);
            }
        };
        addKeyListener(keyListener);
        setFocusable(true);
    }

    public void move() {
        ball.move();
        racquet.move();
    }

    public void reset() {

    }

    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        Graphics2D g2d = (Graphics2D) graphics;
        g2d.setColor(Color.BLACK);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        ball.paint(g2d);
        racquet.paint(g2d);
    }

    public void gameOver() {
        JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
        game.stopGame();
    }


    public Racquet getRacquet() {
        return racquet;
    }

    public void setRacquet(Racquet racquet) {
         this.racquet = racquet;
    }
}

这是我的 LobbyPanel.java:

public class LobbyPanel extends JPanel implements ActionListener {

    private static final JLabel labelForUserTextField = new JLabel("Username");
    private JTextField userName = new JTextField("", 20);
    private JButton startButton = new JButton("Play!");
    private JButton highScoreButton = new JButton("View Best");
    private JButton cancelButton = new JButton("Cancel");
    private Game game;

    public LobbyPanel(Game game) {

        startButton.addActionListener(this);

        this.game = game;
        this.setLayout(new GridBagLayout());
        this.setBorder(new EmptyBorder(10, 10, 10, 10));
        GridBagConstraints labelConst = new GridBagConstraints();
        labelConst.insets = new Insets(3, 3, 3, 3);

        labelConst.gridx = 0;
        labelConst.gridy = 0;
        this.add(labelForUserTextField, labelConst);
        labelConst.gridx = 1;
        this.add(userName, labelConst);
        labelConst.gridx = 0;
        labelConst.gridy = 1;
        this.add(cancelButton, labelConst);
        labelConst.gridx = 1;
        this.add(highScoreButton, labelConst);
        labelConst.gridx = 2;
        this.add(startButton, labelConst);

    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        try {
            if(actionEvent.getSource() == this.startButton) {
                this.game.playGame();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

我希望有人能弄清楚为什么这段代码不能按预期工作。 提前谢谢!

【问题讨论】:

  • public class GamePanel extends JPanel { .. public void paint(Graphics graphics) { 对于任何JComponent(其中JPanel 是其中之一),该方法应该是paintComponent(Graphics)
  • 欢迎来到 Stack Overflow!我想 95% 的代码与你的问题无关。请创建一个 Minimal, Complete and Verifiable Example 来证明您的问题。
  • 除了@AndrewThompson 所说的,你不应该使用while (true) 循环,而是使用Swing Timer 并且永远不要在Swing 应用程序中使用Thread.sleep(...),否则它会阻塞EDT
  • “好吧,我可以移除 Racquet 和 Ball 类......” 所以你知道,或者至少强烈怀疑,某些部分是不相关的。删除它们并测试该理论! “我不知道问题在我的代码中的确切位置” 按照@JoeC 的建议创建minimal reproducible example 的部分好处是您会发现!如果您懒得花精力去找出答案,为什么要找其他人?
  • @Frakcool “你不应该使用 while (true) 循环” 很好发现!诚然,我只关注代码,直到有一个 MCVE,在我的 IDE 中编译,按照我的口味格式化。

标签: java swing cardlayout


【解决方案1】:

发现问题是Frakcool 提到的:while(true){... 阻止了 GUI,所以我用线程替换它,现在它可以工作了。

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多