【问题标题】:KeyListener class becomes unresponsive after game being resetKeyListener 类在游戏重置后变得无响应
【发布时间】:2014-07-08 01:36:35
【问题描述】:

我正在用 java 编写一个简单的蛇应用程序我有一个包含游戏的 gamePanel 并将其添加到 JFrame Window 类中,当我第一次启动游戏时,keylistener 工作正常但是当游戏丢失时(按下按钮时,游戏会自行重置,但按键侦听器变得无响应),我看不出它应该变得无响应的任何原因,我没有对它做任何事情

class Window extends JFrame {

    private static final long serialVersionUID = -2542001418764869760L;
    private final ButtonPanel buttonPanel;
    private GamePanel gamePanel;
    private ThreadsController c;

    // now size of the game can change only by modifiying this width and height

    public JFrame getFrame() {
        return this;
    }

    public JPanel getGamePanel() {
        return gamePanel;
    }

    public JPanel getButtonPanel() {
        return buttonPanel;
    }

    public Window() throws FileNotFoundException {

        this.setTitle("Snake");
        this.setSize(300, 300);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);

        gamePanel = new GamePanel();
        this.buttonPanel = new ButtonPanel(this, c);

        this.add(new TopPanel(), BorderLayout.NORTH);

        this.add(gamePanel, BorderLayout.CENTER);
        this.add(buttonPanel, BorderLayout.SOUTH);
        this.setVisible(true);
        c = new ThreadsController(gamePanel.getSnakeDepartPosition());
        this.buttonPanel.getExit().addActionListener(
                new ButtonActionListener(this, c));
        this.buttonPanel.getNewGame().addActionListener(
                new ButtonActionListener(this, c));

        c.start();
        this.addKeyListener(new KeyboardListener());
        this.setFocusable(true);
    }

    private class KeyboardListener extends KeyAdapter {

        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()) {
            case KeyEvent.VK_RIGHT:
                // if it's not the opposite direction
                if (ThreadsController.directionSnake != Directions.LEFT)
                    ThreadsController.directionSnake = Directions.RIGHT;
                break;
            case KeyEvent.VK_UP:
                if (ThreadsController.directionSnake != Directions.BOTTOM)
                    ThreadsController.directionSnake = Directions.TOP;
                break;

            case KeyEvent.VK_LEFT:
                if (ThreadsController.directionSnake != Directions.RIGHT)
                    ThreadsController.directionSnake = Directions.LEFT;
                break;

            case KeyEvent.VK_DOWN:
                if (ThreadsController.directionSnake != Directions.TOP)
                    ThreadsController.directionSnake = Directions.BOTTOM;
                break;

            default:
                break;
            }
        }    
    }

}


here is the action listener

    public class ButtonActionListener implements ActionListener {

    private Window frame;
    private ThreadsController t;

    public ButtonActionListener(Window frame, ThreadsController t) {
        this.frame = frame;
        this.t = t;
    }

    @Override
    public void actionPerformed(ActionEvent clickedButton) {
        // TODO Auto-generated method stub
        /*
         * t.setAlive(false);
         * 
         * frame.getContentPane().remove(frame.getGamePanel());
         * 
         * 
         * 
         * frame.add(gamePanel, BorderLayout.CENTER); frame.setVisible(true);
         */GamePanel gamePanel = new GamePanel();
        gamePanel.addKeyListener(new KeyboardListenner());
        frame.add(gamePanel, BorderLayout.CENTER);
        frame.setVisible(true);
        t = new ThreadsController(new Tuple(10, 10));
        t.start();    
    }    
}

【问题讨论】:

    标签: java swing user-interface keylistener


    【解决方案1】:

    KeyEvents 仅针对具有焦点的组件生成。

    当您单击按钮时,按钮现在的焦点不是您的“GamePanel”。你需要使用:

    gamePanel.requestFocusInWindow();
    

    在框架可见之后。

    但是,这并不能解决问题,因为您不能只将新的“GamePanel”添加到框架中,因为您的内容窗格现在将包含两个 GamePanel。如果组件添加到框架的顺序相反,Swing 将绘制组件。因此,您将首先绘制新的 GamePanel,然后将旧的 GamePanel 绘制在顶部。因此,您需要在添加新的 GamePanel 之前移除旧的 GamePanel。

    或者,如果您想重置游戏,更好的方法是在您的 GamePanel 中有一个“重置”方法来重置游戏。不要k

    【讨论】:

    • 很酷的答案,但是如果必须调用 frame.requestFocusInWindow();我只是不知道这里的整个焦点业务,这是一个很好的提示。显然面板根本无法聚焦。
    • OP 依赖于 BorderLayout 的副作用,它只会布局添加到给定位置的最后一个组件,但是,它们不会处理预先存在的控制器,这将是更多关注(恕我直言)......更不用说键绑定;)
    • @Jenny,面板在默认情况下是不可聚焦的,但它们可以成为可聚焦的。通常的建议是使用Key Bindings,这样您就不会遇到焦点问题。查看Motion Using the Keyboard 了解更多信息。
    • @MadProgrammer,是的,它只会布局添加的最后一个组件,但是由于 ZOrder 逻辑,只有添加的第一个组件是可见的,因为它是最后绘制的(并且它仍然具有有效的位置/大小信息,假设框架没有调整大小)。这就是为什么我建议在添加第二个游戏面板之前需要删除第一个游戏面板。
    • @camickr 哦,同意删除第一个面板,没问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 2010-09-22
    • 1970-01-01
    • 2018-10-04
    相关资源
    最近更新 更多