【问题标题】:Using Key Listeners to change a JFrame使用 Key Listeners 更改 JFrame
【发布时间】:2015-04-26 13:08:47
【问题描述】:

我正在制作一个简单的 Snake 游戏,除了 Key Listener 之外,一切似乎都在工作。根据我所看到的一切,它是正确编写的。

游戏出现了,但即使您按下箭头键,蛇也不会移动。

提前致谢!

这是主要的:

    public class SnakeFrame extends JFrame implements KeyListener{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private int direction;
    private World w;
    private WorldComponant wc;
    GameLoopThread glt;

    public SnakeFrame(){
        setSize(420,440);
        setTitle("Snake");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Container c = getContentPane();
        c.setLayout(new BorderLayout());

        w = new World();
        wc = new WorldComponant(w);
        glt = new GameLoopThread(wc);
        direction = Direction.SOUTH;

        c.add(wc);
    }

    public static void main(String[] args){
        SnakeFrame s = new SnakeFrame();
        s.setVisible(true);
    }

    public void keyPressed(KeyEvent e) {
        switch(e.getKeyCode()){
        case (KeyEvent.VK_UP):{
            if(direction!=Direction.SOUTH){
                direction = Direction.NORTH;
                wc.move(direction);
            }
            break;
        }
        case (KeyEvent.VK_DOWN):{
            if(direction!=Direction.NORTH){
                direction = Direction.SOUTH;
                wc.move(direction);
            }
            break;
        }
        case (KeyEvent.VK_RIGHT):{
            if(direction!=Direction.WEST){
                direction = Direction.EAST;
                wc.move(direction);
            }
            break;
        }
        case (KeyEvent.VK_LEFT):{
            if(direction!=Direction.EAST){
                direction = Direction.WEST;
                wc.move(direction);
            }
            break;
        }
        }
}

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

}

这是 GameLoopThread:

public class GameLoopThread extends Thread{

    private WorldComponant sc;

    public GameLoopThread(WorldComponant sc){
        this.sc = sc;
    }



    public void run(){
        while(true){
            sc.repaint();
            try{
                Thread.sleep(100);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

这是移动方法。它在 World Class 中,也从 WorldComponant 调用:

public void move(int direction) {
        Point head = snake.peekFirst();
        Point newPt = head;
        switch(direction){
        case (Direction.NORTH):{
            newPt = new Point(head.x, head.y-1);
            break;
        }
        case (Direction.SOUTH):{
            newPt = new Point(head.x, head.y+1);
            break;
        }
        case (Direction.WEST):{
            newPt = new Point(head.x-1, head.y);
            break;
        }
        case (Direction.EAST):{
            newPt = new Point(head.x+1, head.y);
            break;
        }

        }

        snake.remove(snake.peekLast());

        if(newPt.equals(food)){
            Point addPt = (Point) newPt.clone(); 

            switch(direction){
            case (Direction.NORTH):{
                newPt = new Point(head.x, head.y-1);
                break;
            }
            case (Direction.SOUTH):{
                newPt = new Point(head.x, head.y+1);
                break;
            }
            case (Direction.WEST):{
                newPt = new Point(head.x-1, head.y);
                break;
            }
            case (Direction.EAST):{
                newPt = new Point(head.x+1, head.y);
                break;
            }

            }
            score++;
            snake.add(addPt);
            placeFood();

        }
        else if(newPt.x < 0 || newPt.x > gridw - 1){
            generateDefaultSnake();
            JOptionPane.showMessageDialog(null, "YOU LOST! :(", "Loser!", JOptionPane.ERROR_MESSAGE);
            return;
        }
        else if(newPt.y < 0 || newPt.y > gridh - 1){
            generateDefaultSnake();
            JOptionPane.showMessageDialog(null, "YOU LOST! :(", "Loser!", JOptionPane.ERROR_MESSAGE);
            return;
        }
        else if(snake.contains(newPt)){
            generateDefaultSnake();
            JOptionPane.showMessageDialog(null, "YOU LOST! :(", "Loser!", JOptionPane.ERROR_MESSAGE);
            return;
        }

        snake.add(newPt);

    }

【问题讨论】:

  • 您是否曾经将已实现的 keylistener 添加到您的 JFrame 中?另一方面,如果您的 WorldComponant 类恰好是 JComponent 的子类,您应该考虑使用键绑定。
  • 不要使用 KeyListener!有关使用 Key Bindings 的更好方法,请参阅 Motion Using the Keyboard

标签: java swing user-interface jframe keylistener


【解决方案1】:

在使JFrame 可见后,尝试在JFrame 上调用setFocusable(true)requestFocusInWindow()。 (虽然,我认为 setFocusable(true) 对于 JFrame 来说不是必需的)。

How to Write a Key Listener

How to Use the Focus Subsystem

【讨论】:

    【解决方案2】:

    KeyListerner 是众所周知的麻烦,但在尝试将它们直接添加到 JFrame 时更糟。 JFrame 在它和用户之间有一个JRootPanecontentPane 和可能的glassPane,所有这些都可以窃取焦点并阻止KeyListener 接收关键事件。

    更好的解决方案是使用键绑定 api 并将其注册到自定义 contentPane

    详情请见How to use key bindings

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-08
      • 1970-01-01
      • 1970-01-01
      • 2020-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-30
      相关资源
      最近更新 更多