我KeyListener在代码(游戏或其他方式)中使用s作为屏幕对象对用户键输入做出反应的方式。这是我的代码:
KeyListener
public class MyGame extends JFrame { static int up = KeyEvent.VK_UP; static int right = KeyEvent.VK_RIGHT; static int down = KeyEvent.VK_DOWN; static int left = KeyEvent.VK_LEFT; static int fire = KeyEvent.VK_Q; public MyGame() { // Do all the layout management and what not... JLabel obj1 = new JLabel(); JLabel obj2 = new JLabel(); obj1.addKeyListener(new MyKeyListener()); obj2.addKeyListener(new MyKeyListener()); add(obj1); add(obj2); // Do other GUI things... } static void move(int direction, Object source) { // do something } static void fire(Object source) { // do something } static void rebindKey(int newKey, String oldKey) { // Depends on your GUI implementation. // Detecting the new key by a KeyListener is the way to go this time. if (oldKey.equals("up")) up = newKey; if (oldKey.equals("down")) down = newKey; // ... } public static void main(String[] args) { new MyGame(); } private static class MyKeyListener extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { Object source = e.getSource(); int action = e.getExtendedKeyCode(); /* Will not work if you want to allow rebinding keys since case variables must be constants. switch (action) { case up: move(1, source); case right: move(2, source); case down: move(3, source); case left: move(4, source); case fire: fire(source); ... } */ if (action == up) move(1, source); else if (action == right) move(2, source); else if (action == down) move(3, source); else if (action == left) move(4, source); else if (action == fire) fire(source); } } }
我的响应能力有问题:
该答案说明并演示了如何使用键绑定代替键侦听器来进行教学。它不是
它是
对于那些在关键听众方面遇到麻烦的人,我要发表的答案是。 回答; 阅读有关键绑定的Swing教程。
我不想阅读手册,告诉我为什么我想使用键绑定而不是已经拥有的漂亮代码!
好吧,Swing教程说明了
该代码更易于阅读。
好的,你说服了我尝试一下。它是如何工作的?
键绑定涉及2个对象InputMap和ActionMap。InputMap将用户输入映射到动作名称,ActionMap将动作名称映射到Action。当用户按下某个键时,将在输入映射图中搜索该键并找到一个动作名称,然后在该动作图中搜索该动作名称并执行该动作。
好问题!你将看到,这是使键绑定更易于管理(禁用,重新绑定等)的事情之一。
否(Swing教程中有工作示例)。
You suck! I hate you!
以下是进行单个键绑定的方法:
myComponent.getInputMap().put("userInput", "myAction"); myComponent.getActionMap().put("myAction", action);
请注意,有3 InputMap秒对不同的聚焦状态做出反应:
myComponent.getInputMap(JComponent.WHEN_FOCUSED); myComponent.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); myComponent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
WHEN_FOCUSED
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
WHEN_IN_FOCUSED_WINDOW
public class MyGame extends JFrame { private static final int IFW = JComponent.WHEN_IN_FOCUSED_WINDOW; private static final String MOVE_UP = "move up"; private static final String MOVE_DOWN = "move down"; private static final String FIRE = "move fire"; static JLabel obj1 = new JLabel(); static JLabel obj2 = new JLabel(); public MyGame() { // Do all the layout management and what not... obj1.getInputMap(IFW).put(KeyStroke.getKeyStroke("UP"), MOVE_UP); obj1.getInputMap(IFW).put(KeyStroke.getKeyStroke("DOWN"), MOVE_DOWN); // ... obj1.getInputMap(IFW).put(KeyStroke.getKeyStroke("control CONTROL"), FIRE); obj2.getInputMap(IFW).put(KeyStroke.getKeyStroke("W"), MOVE_UP); obj2.getInputMap(IFW).put(KeyStroke.getKeyStroke("S"), MOVE_DOWN); // ... obj2.getInputMap(IFW).put(KeyStroke.getKeyStroke("T"), FIRE); obj1.getActionMap().put(MOVE_UP, new MoveAction(1, 1)); obj1.getActionMap().put(MOVE_DOWN, new MoveAction(2, 1)); // ... obj1.getActionMap().put(FIRE, new FireAction(1)); obj2.getActionMap().put(MOVE_UP, new MoveAction(1, 2)); obj2.getActionMap().put(MOVE_DOWN, new MoveAction(2, 2)); // ... obj2.getActionMap().put(FIRE, new FireAction(2)); // In practice you would probably create your own objects instead of the JLabels. // Then you can create a convenience method obj.inputMapPut(String ks, String a) // equivalent to obj.getInputMap(IFW).put(KeyStroke.getKeyStroke(ks), a); // and something similar for the action map. add(obj1); add(obj2); // Do other GUI things... } static void rebindKey(KeyEvent ke, String oldKey) { // Depends on your GUI implementation. // Detecting the new key by a KeyListener is the way to go this time. obj1.getInputMap(IFW).remove(KeyStroke.getKeyStroke(oldKey)); // Removing can also be done by assigning the action name "none". obj1.getInputMap(IFW).put(KeyStroke.getKeyStrokeForEvent(ke), obj1.getInputMap(IFW).get(KeyStroke.getKeyStroke(oldKey))); // You can drop the remove action if you want a secondary key for the action. } public static void main(String[] args) { new MyGame(); } private class MoveAction extends AbstractAction { int direction; int player; MoveAction(int direction, int player) { this.direction = direction; this.player = player; } @Override public void actionPerformed(ActionEvent e) { // Same as the move method in the question code. // Player can be detected by e.getSource() instead and call its own move method. } } private class FireAction extends AbstractAction { int player; FireAction(int player) { this.player = player; } @Override public void actionPerformed(ActionEvent e) { // Same as the fire method in the question code. // Player can be detected by e.getSource() instead, and call its own fire method. // If so then remove the constructor. } } }
你可以看到,将输入映射与动作映射分开可以实现可重用的代码并更好地控制绑定。此外,如果需要功能,也可以直接控制操作。例如:
FireAction p1Fire = new FireAction(1); p1Fire.setEnabled(false); // Disable the action (for both players in this case).
有关更多信息,请参见“ 操作”教程。
我看到你对4个键(方向)使用了1个动作(移动),对1个键使用了1个动作(触发)。为什么不给每个键一个自己的动作,或者不给所有键一个相同的动作,并理清在该动作内部做什么(例如在移动情况下)?
好点子。从技术上讲,你可以同时进行这两种操作,但是你必须考虑什么才是有意义的,以及什么才能简化管理和重用代码。在这里,我假设在所有方向上的移动都是相似的,而发射是不同的,所以我选择了这种方法。
我看到很多KeyStroke用过的,那是什么?他们像KeyEvent吗?
KeyStroke
KeyEvent
是的,它们具有类似的功能,但更适合在此使用。请参阅其API以获取信息以及如何创建它们。
有什么问题吗 有改善吗?有什么建议吗?发表评论。有更好的答案吗?发表它。