JPanel不想关注,因此KeyAdapter不起作用

时间:2014-05-23 03:33:26

标签: java swing jpanel keylistener

背景

我有一个简单的游戏。我有一个JPanel课,每个东西都有(菜单,游戏,游戏结束)。

然后我决定,我应该让我的游戏更好,我制作了两个面板(一个用于菜单,第二个用于游戏lvls)。

每件事都很好,但我的KeyAdapter课程不适用于JPanel。我不知道为什么它不想集中注意力。

我有我的:

  • 扩展JFrame的主要类,此处我将面板(和KeyListener添加到第一个面板)

    public class JavaGame2 extends JFrame {
    
        public JavaGame2(){
            gamePanel = new GamePanel();          
            menuPanel = new MenuPanel();
            setContentPane(menuPanel);
    
            menuPanel.addKeyListener(new KeyListener() {
    
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_UP) {
                        menuPanel.changeCursor();
                    }
                    if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                        menuPanel.changeCursor();
                    }
                    if (menuPanel.getCursorPos()==1){
                        if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
    
                            setContentPane(gamePanel);
                            //add(gamePanel);
                        }
                    }
                    else{
                        if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
                            System.exit(0);
                        }
                    }
                }
    
            });
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setSize(800, 600);
            setLocationRelativeTo(null);
            setTitle("JavaGame2");
            setResizable(false);    
        }
        public static void main(String[] args) {
            JFrame jgame = new JavaGame2();
            jgame.setVisible(true);
        }
    }
    
  • MenuPanel类扩展JPanel

    public class MenuPanel extends JPanel implements ActionListener{
    
        public MenuPanel(){
            setFocusable(true);
            setBackground(Color.BLACK);
            setDoubleBuffered(true);
            setSize(800,600);
        }
        public void actionPerformed(ActionEvent e) {
        }
    }
    
  • 此处GamePanel

    public class GamePanel extends JPanel implements ActionListener{
    
        public GamePanel (){
            addKeyListener(new GameAdapter());
            setFocusable(true);
            requestFocus();
            setBackground(Color.BLACK);
            setDoubleBuffered(true);
            setSize(800,600);
        }
    
        private class GameAdapter extends KeyAdapter{
    
            public void keyReleased(KeyEvent e) {
                ship.keyReleased(e);
            }
    
            public void keyPressed(KeyEvent e) {
                ship.keyPressed(e);
            }
        }
    }
    

它不起作用。 GamePanel我不想专注,我试着去做我读过的每一件事。 我想你会说JPanel不是可集中的组成部分。但当有一个小组时,它在某种程度上有效。

如何解决此焦点问题? 也许你会说你更喜欢不使用KeyAdapter,但我觉得它在我的代码中看起来很不错。

setFocusable()?还是requestFocus()requestFocusInWindow()?我应该如何使用它们?也许我之前有过错,这不是我的第一个问题?

提前致谢。

感谢您的编辑。

1 个答案:

答案 0 :(得分:3)

简短回答,使用key bindings API,它允许您在触发关键事件之前控制组件所需的焦点水平。

更长的答案,活动面板需要具有键盘焦点。您可以使用requestFocusInWindow,但无法保证组件实际上会获得焦点。什么时候打电话这是件棘手的事。您可以尝试覆盖addNotify面板并打电话到那里,只要确保先拨打super.addNotify,否则就会发生奇怪的事情

如果组件失去焦点,您还需要考虑会发生什么

作为旁注:

  • setDoubleBuffered(true);无关紧要,因为默认情况下Swing组件是双缓冲的。通常,如果要打印组件,可以禁用此功能。通过调用它没有坏处
  • 在组件上调用setSize是无关紧要的,因为组件将在布局管理器的控制下,这将决定组件本身的大小。您最好覆盖getPreferredSize并为布局管理器返回适当的大小
  • setSize上拨打JFrame也是一个坏主意。框架具有边框,这意味着您的可视区域将是frame size - the frames border insets,这将小于您指定的800x600。最好使用之前的评论,并在pack上调用JFrame,这会在内容周围打包框架,以满足内容要求......
  • 就个人而言,我还会将KeyListener本地化为实际组件本身,这样可以让组件充当它自己的控制器,使其更具可移植性......恕我直言

更新了控制器构思......

A"真的"简化的概念是拥有某种"控制器"菜单和游戏面板可以通过,例如...

进行通信
public interface GameController {
    public void showMenu();
    public void showGame();
}

然后,您可以将此界面的引用传递给MenuPanel ...

public class MenuPanel extends JPanel implements ActionListener{

    public MenuPanel(GameController controller){
        //...
    }

    public Dimension getPreferredSize() {
        return new Dimension(800, 600);
    }

GamePanel ...

public class GamePanel extends JPanel implements ActionListener{

    public GamePanel (GameController controller){
        //...
    }

    public Dimension getPreferredSize() {
        return new Dimension(800, 600);
    }

显然,您需要构建控制器的实现...

public class CardLayoutGameController implements GameController {
    public static final String GAME_PANEL = "GamePanel";
    public static final String MENU_PANEL = "MenuPanel";

    private Container container;
    private CardLayout cardLayout;

    public CardLayoutGameController(Container parent, CardLayout layout) {
        container = parent;
        cardLayout = layout;
    }

    public void showMenu() {
        cardLayout.show(container, MENU_PANEL);
    }

    public void showGame() {
        cardLayout.show(container, GAME_PANEL);
    }
}

然后,您将围绕此控制器构建UI,例如......

public class JavaGame2 extends JFrame {

    public JavaGame2(){
        CardLayout layout = new CardLayout();
        setLayout(layout);
        GameController controller = new CardLayoutGameController(getContentPane(), layout);

        gamePanel = new GamePanel(controller);          
        menuPanel = new MenuPanel(controller);

        add(gamePanel, CardLayoutGameController.GAME_PANEL);
        add(menuPanel, CardLayoutGameController.MENU_PANEL);

        controller.showMenu();

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setTitle("JavaGame2");
        setResizable(false);    
    }
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                JFrame jgame = new JavaGame2();
                jgame.setVisible(true);
            }
        });
    }
}

这只是一个"例子"为了激发这个想法,我们没有对此进行过测试,只是在这里被黑了,所以它可能会爆炸:P