如何从ActionMap的AbstractAction中获取按键码
问题:从ActionMap的AbstractAction中获取按键码
我想从动作映射(ActionMap)中的AbstractAction获取对应按键码,目前正在尝试把所有按键的按下状态存储在KeyInputManager内部的HashMap中。已经遍历有效按键码并为每个按键注册了AbstractAction,但在actionPerformed方法里无法获取对应按键码来更新状态。
原实现代码
遍历注册Action的代码:
for (int key = 37; key <= 122; key++) { this.key = key; if(!KeyEvent.getKeyText(key).contains("Unknown keyCode")) { if(KeyInputManager.getInputManager().getOrDefault(key, null) == null) KeyInputManager.getInputManager().put(key, true); component.getActionMap().put(KeyEvent.getKeyText(key), new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { int keyCode = // TODO: GET KEY CODE HERE KeyInputManager.getInputManager().replace(keyCode, true); } }); component.getInputMap().put(KeyStroke.getKeyStroke(key, 0, false), KeyEvent.getKeyText(key)); } }
KeyInputManager代码:
public class KeyInputManager { private static final HashMap<Integer, Boolean> keysDown = new HashMap<Integer, Boolean>(); public static final boolean keyDown(int keyCode) { return keysDown.getOrDefault(keyCode, false); } public static HashMap<Integer, Boolean> getInputManager() { return keysDown; } }
解决方案
方案1:使用Effectively Final变量
匿名内部类只能访问final或**实际不可变(effectively final)**的外部变量,所以在循环内将key赋值给一个局部final变量,即可在action中直接引用:
for (int key = 37; key <= 122; key++) { // 定义实际不可变的局部变量,供匿名内部类访问 final int currentKey = key; if(!KeyEvent.getKeyText(currentKey).contains("Unknown keyCode")) { if(KeyInputManager.getInputManager().getOrDefault(currentKey, null) == null) KeyInputManager.getInputManager().put(currentKey, true); component.getActionMap().put(KeyEvent.getKeyText(currentKey), new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { int keyCode = currentKey; // 直接使用final变量获取按键码 KeyInputManager.getInputManager().replace(keyCode, true); } }); component.getInputMap().put(KeyStroke.getKeyStroke(currentKey, 0, false), KeyEvent.getKeyText(currentKey)); } }
方案2:自定义带按键码的Action类
如果需要更灵活的扩展,可以自定义继承AbstractAction的类,在构造时传入按键码:
// 自定义Action类,携带按键码 class KeyPressAction extends AbstractAction { private final int keyCode; public KeyPressAction(int keyCode) { this.keyCode = keyCode; } @Override public void actionPerformed(ActionEvent e) { KeyInputManager.getInputManager().replace(keyCode, true); } }
循环中使用自定义Action:
for (int key = 37; key <= 122; key++) { if(!KeyEvent.getKeyText(key).contains("Unknown keyCode")) { if(KeyInputManager.getInputManager().getOrDefault(key, null) == null) KeyInputManager.getInputManager().put(key, true); // 传入当前按键码创建Action实例 component.getActionMap().put(KeyEvent.getKeyText(key), new KeyPressAction(key)); component.getInputMap().put(KeyStroke.getKeyStroke(key, 0, false), KeyEvent.getKeyText(key)); } }
额外优化:封装KeyInputManager的状态修改
直接返回HashMap引用会导致外部可以随意修改内部状态,建议添加封装方法替代暴露整个Map:
public class KeyInputManager { private static final HashMap<Integer, Boolean> keysDown = new HashMap<>(); public static boolean keyDown(int keyCode) { return keysDown.getOrDefault(keyCode, false); } // 封装状态修改方法,避免暴露内部Map public static void setKeyDown(int keyCode, boolean isDown) { keysDown.put(keyCode, isDown); } }
此时Action中调用修改方法即可:
// 在actionPerformed中替换为 KeyInputManager.setKeyDown(keyCode, true);
内容的提问来源于stack exchange,提问作者user17820402
相关产品推荐
相关产品推荐

