- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在使用 KeyListener
s 在我的代码(游戏或其他)中作为我的屏幕对象对用户键输入使用react的方式。这是我的代码:
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);
}
}
}
我的响应速度有问题:
为什么会发生这种情况,我该如何解决?
最佳答案
此答案解释并演示了如何使用键绑定(bind)而不是键监听器来达到教育目的。这不是
是
回答;阅读 Swing tutorial on key bindings .
I don't want to read manuals, tell me why I would want to use key bindings instead of the beautiful code I have already!
好吧,Swing 教程 对此进行了解释
OK, you convinced me to try it out. How does it work?
tutorial 有一个很好的部分。键绑定(bind)涉及 2 个对象 InputMap
和 ActionMap
。 InputMap
将用户输入映射到操作名称,ActionMap
将操作名称映射到Action
。当用户按下一个键时,在输入映射中搜索该键并找到一个 Action 名称,然后在 Action 映射中搜索 Action 名称并执行该 Action 。
Looks cumbersome. Why not bind the user input to directly to the action and get rid of the action name? Then you need only one map and not two.
好问题!您会发现这是使键绑定(bind)更易于管理(禁用、重新绑定(bind)等)的原因之一。
I want you to give me a full working code of this.
否(Swing 教程 有 working examples)。
You suck!I hate you!
这里是如何进行单键绑定(bind):
myComponent.getInputMap().put("userInput", "myAction");
myComponent.getActionMap().put("myAction", action);
请注意,有 3 个 InputMap
对不同的焦点状态作出 react :
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.
}
}
}
您可以看到,将输入映射与操作映射分开可以实现可重用代码和更好地控制绑定(bind)。此外,如果您需要该功能,您还可以直接控制一个 Action。例如:
FireAction p1Fire = new FireAction(1);
p1Fire.setEnabled(false); // Disable the action (for both players in this case).
参见 Action tutorial获取更多信息。
I see that you used 1 action, move, for 4 keys (directions) and 1 action, fire, for 1 key. Why not give each key its own action, or give all keys the same action and sort out what to do inside the action (like in the move case)?
好点。从技术上讲,您可以两者都做,但您必须考虑什么是有意义的,什么允许轻松管理和可重用代码。在这里,我假设所有方向的移动都是相似的,而射击是不同的,所以我选择了这种方法。
I see a lot of
KeyStroke
s used, what are those? Are they like aKeyEvent
?
是的,它们具有类似的功能,但更适合在这里使用。查看他们的 API有关信息以及如何创建它们的信息。
有问题吗?改进?建议?发表评论。有更好的答案吗?发布它。
关于java - 如何使用 Key Bindings 而不是 Key Listeners,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22741215/
我正在尝试捕捉评论状态事件,例如有人正在关闭它。并在从插件中获得任何生命迹象之后。向日志文件(从任何日志级别)或 STDOUT 发送一行。atlassian-plugins.xml 看起来像这样:
我在跑; sass --watch --style compressed --sourcemap css/sass:css 我得到了; NameError: uninitialized constan
您好,我正在创建一个 android 应用程序作为 ejabbered 服务器的 XMPP 客户端。 但我真的很困惑,因为我看到我可以将消息作为数据包或消息发送,我也可以使用 PacketListen
我有一个 imageview - 它的属性 -focusable 和 focusableintouchmode 都设置为 true 我已经在我的 Activity 中实现了 onFocus
我有一个查询来查找指定条形码的文档 ID: Future findBarcode() async { String searchBarcode = await BarcodeScanner.sca
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 5 年前。 Improve
这可能是一个非常基本的问题,但我就是不明白。使用 Express.js 创建应用和启动应用监听 1234 端口有什么区别,例如: var express = require('express'); v
所以我想知道什么是更好看的解决方案/有什么区别以及在决定制作多个监听器(1 个监听器用于 1 个按钮)还是仅 1 个 ActionListener 用于 GUI 中的所有按钮(大约 10 个按钮),并
我目前正在尝试制作一个聊天室服务器。我正在努力做到这一点,以便我可以同时监听新请求的连接和监听从已建立的连接发送的消息。 我可以用它来监听请求的连接: def reqlisten(): glo
有没有办法在事件监听器方法中访问类上下文并有可能删除监听器? 示例 1: import {EventEmitter} from "events"; export default class Event
应用程序在本地主机上工作正常。但是当它连接到服务器时出现错误。 我通过端口 22 连接服务器 这是错误 Error: listen EADDRNOTAVAIL Error: listen EADDRN
我有类似的东西: $scope.$on(config.SOME_CONSTANT, ()=> { activate(); // plus a bunch of instantiatio
我的 HTML 页面上有以下 Controller : ... ... 此子 Controller 映射到以下 c
我的 HTML 页面上有以下 Controller : ... ... 此子 Controller 映射到以下 c
我构建了一个自定义属性并将其添加到可观察列表中。但是,如果属性内容发生更改,则不会调用任何监听器。以下代码片段向您展示了“建筑”: public static final class TestObje
这里我不明白这两种方法的基本区别是什么。 var events = require('events'); var eventEmitter = new events.EventEmitter(); v
我正在尝试使用 grunt-express 设置 Grunt 来启动我的 Express 服务器。读完docs后和 this SO question ,我还是想不通。我已经为我的 Grunt 文件尝试
如果这里问题的某些方面不清楚,我深表歉意,因为我是 Node 和 javascript 的新手。请询问更多详情 我有一个使用 socketio 连接到 firebase 的 Node 应用程序。在 h
情况 我可能没有使用传统意义上的 PHPUnit。我正在使用带有 Selenium 2 的 PHPUnit。我们有这个想法来记录 Selenium 以“重现步骤”的方式执行的操作。这意味着如果我们调用
我正在尝试学习在 struts2 中使用 session 。所以,我只想实现一个登录/注销、配置文件应用程序。我正在关注互联网上提供的基本教程。但是,它根本不起作用。请帮助我解决以下问题如何解决。 S
我是一名优秀的程序员,十分优秀!