【问题标题】:Full screen Window won't get keyboard input using KeyListener or KeyBoardFocusManager全屏窗口不会使用 KeyListener 或 KeyBoardFocusManager 获得键盘输入
【发布时间】:2012-06-26 02:13:59
【问题描述】:

我无法让我的KeyBoardFocusManger 与我的全屏Window 一起工作。无论如何,它只是不会获得键盘输入。我使用System.exit(0)println() 来查找对keypressed/released/typed 方法的任何调用,但没有抛出任何错误。我试过KeyListeners;但是在我读了this之后,我改成了KeyboardFocusManager,同样的事情仍然发生。我真的很绝望;据我判断,Window 没有获得键盘焦点?

这是我的主要内容:

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            // Determine if full-screen mode is supported directly
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            if (gs.isFullScreenSupported()) {
                Frame frame = new Frame(gs.getDefaultConfiguration());
                SpaceInvaderUI spaceInvaderUI = new SpaceInvaderUI(frame);
                // Enter full-screen mode
                gs.setFullScreenWindow(spaceInvaderUI);
            } else {
                JOptionPane.showMessageDialog(null, "Does not support full screen!", "Error 0x01", JOptionPane.ERROR_MESSAGE);
                System.exit(1);
            }
        }
    });
}

这里是包含KeyBoardFocusManger的UI,并被添加到addListeners()方法中:

class SpaceInvaderUI extends Window {

    private JPanel drawingPanel;
    private Image background;
    private JButton btnExit;

    public SpaceInvaderUI(Frame frame) {
        super(frame);
        try {
            background = ImageIO.read(getClass().getResourceAsStream("background.png"));
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "Could not extract resource: " + ex.getMessage(), "Error 0x02", JOptionPane.ERROR_MESSAGE);
            System.exit(2);
        }
        createWindow();
    }

    private void createComponents() throws HeadlessException {
        drawingPanel = new DrawingPanel(background, this);
        btnExit = new JButton("Exit");
    }

    private void createWindow() {
        createComponents();
        addListeners();
        addComponentsToWindow();
    }

    private void addComponentsToWindow() {
        add(drawingPanel, BorderLayout.CENTER);
        add(btnExit, BorderLayout.SOUTH);
    }

    private void addListeners() {
        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.addKeyEventDispatcher(new MyDispatcher());
        btnExit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                System.exit(0);
            }
        });
    }

    private class MyDispatcher implements KeyEventDispatcher {

        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                System.out.println("pressed");
                System.exit(0);
            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                System.out.println("released");
                System.exit(0);
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
                System.out.println("Typed");
                System.exit(0);
            }
            return false;
        }
    }
}

退出按钮只是因为我厌倦了通过任务管理器杀死我的应用程序。最后,这是我的面板,游戏将在该面板上进行,我的背景将在上面绘制:

public class DrawingPanel extends JPanel {

    private final Image background;
    private final SpaceInvaderUI invaderUI;

    DrawingPanel(Image background, SpaceInvaderUI invaderUI) {
        this.background = background;
        this.invaderUI = invaderUI;
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        grphcs.drawImage(background.getScaledInstance((int) invaderUI.getWidth(), (int) invaderUI.getHeight(), Image.SCALE_SMOOTH), 0, 0, this);
    }
}

提前谢谢你。

编辑:我现在尝试在我的drawingPanel 上使用键绑定,但是当我按下 f2 时仍然没有任何反应:

class SpaceInvaderUI extends Window {

    private JPanel drawingPanel;
    private Image background;
    private JButton btnExit;

    public SpaceInvaderUI(Frame frame) {
        super(frame);
        try {
            background = ImageIO.read(getClass().getResourceAsStream("background.png"));
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "Could not extract resource: " + ex.getMessage(), "Error 0x02", JOptionPane.ERROR_MESSAGE);
            System.exit(2);
        }
        createWindow();
    }

    private void createComponents() throws HeadlessException {
        drawingPanel = new DrawingPanel(background, this);
        btnExit = new JButton("Exit");
    }

    private void createWindow() {
        createComponents();
        addListeners();
        addComponentsToWindow();
    }

    private void addComponentsToWindow() {
        add(drawingPanel, BorderLayout.CENTER);
        add(btnExit, BorderLayout.SOUTH);
    }

    private void addListeners() {
        Action exit = new AbstractAction() {

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        };
        drawingPanel.getInputMap().put(KeyStroke.getKeyStroke("F2"),
                exit);
        btnExit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                System.exit(0);
            }
        });
    }
}

【问题讨论】:

  • 它不是框架而是窗口,我可以使用按钮将其关闭,但我希望游戏使用“Esc”键退出并调出菜单等
  • 那么我猜 KeyBinding 正是适合你的方法。

标签: java swing fullscreen keylistener key-bindings


【解决方案1】:

为什么在 Swing GUI 中使用 AWT 组件?我担心(但不确定)这样做,您可能会失去一些 Swing 功能。

如果您只是捕获选择键选择键击来控制游戏,请考虑使用Key Bindings

编辑
不,AWT 组件没有问题,但仍然可能不应该使用。

编辑 2
由于某种原因,您的顶级窗口没有集中。继续测试代码...

编辑 3
使用 JFrame 对我有用:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test3 {
   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {

         @Override
         public void run() {
            GraphicsEnvironment ge = GraphicsEnvironment
                  .getLocalGraphicsEnvironment();
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            if (gs.isFullScreenSupported()) {
               SpaceInvaderUI spaceInvaderUI = new SpaceInvaderUI(gs.getDefaultConfiguration());
               gs.setFullScreenWindow(spaceInvaderUI);
            } else {
               JOptionPane.showMessageDialog(null,
                     "Does not support full screen!", "Error 0x01",
                     JOptionPane.ERROR_MESSAGE);
               System.exit(1);
            }
         }
      });
   }
}

// class SpaceInvaderUI extends JWindow {
class SpaceInvaderUI extends JFrame {

   private JPanel drawingPanel;
   private Image background;
   private JButton btnExit;

   public SpaceInvaderUI(GraphicsConfiguration gc) {
      super(gc);
      createWindow();
      addKeyBindings();
      setUndecorated(true);
   }

   private void addKeyBindings() {
      int condition = JPanel.WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = drawingPanel.getInputMap(condition );
      ActionMap actionMap = drawingPanel.getActionMap();

      boolean released = false;
      KeyStroke upArrowKeyStrokePressed = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, released );
      String upArrowPressed = "up arrow pressed";
      inputMap.put(upArrowKeyStrokePressed , upArrowPressed);
      actionMap.put(upArrowPressed, new AbstractAction() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            System.out.println("up arrow pressed");
         }
      });

      released = true;
      String upArrowReleased = "up arrow released";
      KeyStroke upArrowKeyStrokeReleased = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, released );
      inputMap.put(upArrowKeyStrokeReleased , upArrowReleased);
      actionMap.put(upArrowReleased , new AbstractAction() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            System.out.println("up arrow released");
         }
      });

   }

   private void createComponents() throws HeadlessException {
      drawingPanel = new DrawingPanel(background, this);
      btnExit = new JButton("Exit");
   }

   private void createWindow() {
      createComponents();
      addListeners();
      addComponentsToWindow();
   }

   private void addComponentsToWindow() {
      add(drawingPanel, BorderLayout.CENTER);
      add(btnExit, BorderLayout.SOUTH);
   }

   private void addListeners() {
//      KeyboardFocusManager manager = KeyboardFocusManager
//            .getCurrentKeyboardFocusManager();
//      manager.addKeyEventDispatcher(new MyDispatcher());
      btnExit.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent ae) {
            System.exit(0);
         }
      });
   }
//
//   private class MyDispatcher implements KeyEventDispatcher {
//
//      @Override
//      public boolean dispatchKeyEvent(KeyEvent e) {
//         System.out.println("in dispatch. KeyEvent := " + e);
//         if (e.getID() == KeyEvent.KEY_PRESSED) {
//            System.out.println("pressed");
//            System.exit(0);
//         } else if (e.getID() == KeyEvent.KEY_RELEASED) {
//            System.out.println("released");
//            System.exit(0);
//         } else if (e.getID() == KeyEvent.KEY_TYPED) {
//            System.out.println("Typed");
//            System.exit(0);
//         }
//         return false;
//      }
//   }
}

class DrawingPanel extends JPanel {

   private final Image background;
   private final SpaceInvaderUI invaderUI;

   DrawingPanel(Image background, SpaceInvaderUI invaderUI) {
      this.background = background;
      this.invaderUI = invaderUI;
      setBackground(Color.pink);
   }

   @Override
   protected void paintComponent(Graphics grphcs) {
      super.paintComponent(grphcs);
   }
}

【讨论】:

  • aaaahhh 我真是太愚蠢了,我专注于将键绑定添加到Window,这显然是不可能的,从未想过将其添加到我的面板中。非常感谢:)
  • 谢谢 看来我可能需要使用一个框架,只是让它不装饰然后设置为全屏。
  • 我可以问一个关于 KeyBinding 的问题吗?我们可以使用InputMapActionMap 在同一个JComponent 上添加多个键,并使用相同的AbstractAction 类吗?
  • @nIcEcOw:是的,您可以添加任意数量的键,并且可以共享操作。
  • 但是,如果每个键都用于执行不同的任务,是否有办法区分该类中的哪个键被按下?就像我使用registerKeyboardAction() 一样,因为它现在已经过时了,在这个我可以指定一个ActionCommand 并在同一个类中区分它,这里是否也有类似的东西?我要问这个问题吗?
【解决方案2】:

如相关FullScreenTest 所示,您可以为按钮键绑定使用相同的Action 实例。

附录:@nIcE cOw 问,我们可以在同一个键上添加多个键 JComponent 通过使用 InputMap ActionMap, 和使用相同的 AbstractAction

是的,多个键绑定是可能的;我有时会调用doClick() 来获得视听反馈,如here 所示。

【讨论】:

  • 我可以问一个关于 KeyBinding 的问题吗?我们可以使用InputMapActionMap 在同一个JComponent 上添加多个键,并使用相同的AbstractAction 类吗?
  • 谢谢,如果我的版本无法正常工作,这似乎是我唯一的选择
猜你喜欢
  • 2011-01-25
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
  • 2014-09-27
  • 2019-08-07
  • 1970-01-01
  • 2017-12-04
  • 2019-01-03
相关资源
最近更新 更多