use*_*551 16 java swing key-events keyevent key-bindings
我KeyListener
在我的代码(游戏或其他)中使用s作为我的屏幕对象对用户键输入做出反应的方式.这是我的代码:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的响应能力有问题:
为什么会发生这种情况,我该如何解决这个问题?
use*_*551 54
这个答案解释并演示了如何使用键绑定而不是键侦听器用于教育目的.它不是
它是
我不想阅读手册,告诉我为什么我要使用键绑定而不是我已经拥有的漂亮代码!
好吧,Swing教程解释了这一点
好的,你说服我尝试一下.它是如何工作的?
本教程有一个很好的部分.键绑定涉及2个对象InputMap
和ActionMap
.InputMap
将用户输入映射到操作名称,ActionMap
将操作名称映射到Action
.当用户按下键时,在输入映射中搜索键并找到动作名称,然后在动作映射中搜索动作名称并执行动作.
看起来很麻烦.为什么不直接将用户输入绑定到操作并删除操作名称?那么你只需要一张地图而不是两张.
好问题!您将看到这是使键绑定更易于管理(禁用,重新绑定等)的事情之一.
我希望你能给我一份完整的工作代码.
不(Swing教程有工作示例).
你好烂!我恨你!
以下是如何进行单键绑定:
myComponent.getInputMap().put("userInput", "myAction");
myComponent.getActionMap().put("myAction", action);
Run Code Online (Sandbox Code Playgroud)
请注意,有3 InputMap
s对不同的焦点状态做出反应:
myComponent.getInputMap(JComponent.WHEN_FOCUSED);
myComponent.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
myComponent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
Run Code Online (Sandbox Code Playgroud)
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.
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以看到将输入映射与操作映射分离可以获得可重用的代码并更好地控制绑定.此外,如果需要该功能,还可以直接控制Action.例如:
FireAction p1Fire = new FireAction(1);
p1Fire.setEnabled(false); // Disable the action (for both players in this case).
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅操作教程.
我看到你使用1个动作,移动,4个键(方向)和1个动作,火,1个键.为什么不给每个键自己的动作,或者给所有键做同样的动作并理清在动作中做什么(比如在移动的情况下)?
好点子.从技术上讲,你可以做到这两点,但你必须考虑什么是有意义的,什么允许简单的管理和可重用的代码.在这里,我假设所有方向的移动都相似,并且射击是不同的,所以我选择了这种方法.
我看到很多
KeyStroke
用过的,那些是什么?他们喜欢KeyEvent
吗?
是的,它们具有类似的功能,但更适合在这里使用.有关信息以及如何创建它们,请参阅其API.
有问题吗?改进?建议?发表评论.有更好的答案吗?发表它.
注意:这不是一个答案,只是一个代码太多的评论:-)
通过getKeyStroke(String)获取keyStrokes是正确的方法 - 但需要仔细阅读api doc:
modifiers := shift | control | ctrl | meta | alt | altGraph
typedID := typed <typedKey>
typedKey := string of length 1 giving Unicode character.
pressedReleasedID := (pressed | released) key
key := KeyEvent key code name, i.e. the name following "VK_".
Run Code Online (Sandbox Code Playgroud)
最后一行应该更确切地说是确切的名称,即大小写:对于向下键,确切的键代码名称是VK_DOWN
,因此参数必须是"DOWN"(不是"向下"或大写/小写字母的任何其他变体)
不完全直观(阅读:我必须自己挖一点)正在获得一个修改键的KeyStroke.即使拼写正确,以下内容也不起作用:
KeyStroke control = getKeyStroke("CONTROL");
Run Code Online (Sandbox Code Playgroud)
在awt事件队列中更深入,创建单个修饰键的keyEvent,并将其自身作为修饰符.要绑定到控制键,您需要笔划:
KeyStroke control = getKeyStroke("ctrl CONTROL");
Run Code Online (Sandbox Code Playgroud)