英文:
JavaFX How can I distinguish between a keyPressed X and a combination of Keys X + Y
问题
我希望我的应用程序(JavaFx 14)在按下键盘上的键"a"时执行某个操作,并且当按下具有相同键"a"和"b"的组合键时,应用程序还会执行另一个操作。目标是只调用一个方法,要么是按下"a"的方法,要么是按下"a" + "b"的方法。我尝试过使用带有键码的可观察列表,但是所有方法都被调用。
private ObservableList<KeyCode> keys = FXCollections.observableArrayList();
private void keyboardShortcuts(Button[] buttons) {
// 收集按下的键
scene.addEventFilter(KeyEvent.KEY_PRESSED, (e) -> {
if (!keys.contains(e.getCode())) {
keys.add(e.getCode());
}
e.consume();
});
// 当释放按键时移除已按下的键
scene.setOnKeyReleased((e) -> {
keys.remove(e.getCode());
e.consume();
});
keys.addListener(new InvalidationListener() {
@Override
public void invalidated(Observable observable) {
if (keys.size() == 1) {
if (keys.contains(KeyCode.A)) {
foo();
}
if (keys.contains(KeyCode.B)) {
foo2();
}
}
if (keys.size() == 2) {
if (keys.contains(KeyCode.A) && keys.contains(KeyCode.B)) {
foo3();
}
}
}
});
}
英文:
I want my application (JavaFx 14) to so something when the key "a" is pressed and I also want the application to do something when a key combination with the same key "a" and "b" is pressed. The goal is to only call one method. the method for pressing a or the method for pressing a +b. I tried doing it with a observable List with keycodes but all methods are called.
private ObservableList<KeyCode> keys = FXCollections.observableArrayList();
private void keyboardShortcuts(Button[] buttons){
// collect pressed key
scene.addEventFilter(KeyEvent.KEY_PRESSED, (e) -> {
if (!keys.contains(e.getCode())) {
keys.add(e.getCode());
}
e.consume();
});
// remove pressed key when it is released
scene.setOnKeyReleased((e) -> {
keys.remove(e.getCode());
e.consume();
});
keys.addListener(new InvalidationListener() {
@Override
public void invalidated(Observable observable) {
if(keys.size() == 1) {
if(keys.contains(KeyCode.A)) {
foo();
}
if(keys.contains(KeyCode.B)) {
foo2();
}
}
if(keys.size() == 2) {
if(keys.contains(KeyCode.A) && keys.contains(KeyCode.B)) {
foo3();
}
}
}
});
}
答案1
得分: 2
以下是您提供的内容的翻译部分:
当用户“同时按下两个键”时,不可能同时发生两个键的按下,因此其中一个键的按下必定会在另一个键之前被检测到。在这种情况下,可能最好的方法是确保其中一个键(比如B)没有自己的功能。这样,用户就会学会始终先按B,然后在按住B的同时按A(这就是我们的输入方式,使用诸如SHIFT和CTRL之类的修饰键)。
如果您真的希望这两个键都有自己的功能,但在“同时按下时”有不同的功能,那么您唯一的选择就是在处理单个键的按下时实现延迟,等待看另一个键是否在该延迟过程结束之前被按下。当然,这会影响响应性能。
以下是实现这一点的代码,使用了一个短暂的(25毫秒)PauseTransition
来实现延迟。(我还修改为使用了ObservableSet
,这样可以清理一些逻辑。)
private ObservableSet<KeyCode> keys = FXCollections.observableSet();
private PauseTransition keyDelay = new PauseTransition(Duration.millis(25));
private void keyboardShortcuts(Scene scene){
// 收集按下的键
scene.addEventFilter(KeyEvent.KEY_PRESSED, (e) -> {
keys.add(e.getCode());
e.consume();
});
// 当按键释放时移除按下的键
scene.setOnKeyReleased((e) -> {
keys.remove(e.getCode());
e.consume();
});
keys.addListener((Change<? extends KeyCode> c) -> {
if (keys.size() <= 1) {
keyDelay.playFromStart();
} else {
keyDelay.stop();
checkKeys();
}
});
keyDelay.setOnFinished(e -> checkKeys());
}
private void checkKeys() {
if(keys.contains(KeyCode.A) && keys.contains(KeyCode.B)) {
System.out.println("A and B");
} else if(keys.contains(KeyCode.A)) {
System.out.println("A only");
} else if(keys.contains(KeyCode.B)) {
System.out.println("B only");
}
}
希望这对您有所帮助!
英文:
When the user "presses two keys", it's impossible for both key presses to happen simultaneously, so one of the key presses will necessarily be detected before the other. Probably the best approach here is to ensure one of the keys (say <kbd>B</kbd>) doesn't have it's own functionality. That way the user will learn to always press <kbd>B</kbd> first, then <kbd>A</kbd> while <kbd>B</kbd> is held down (this is the way we type, using modifier keys such as <kbd>SHIFT</kbd> and <kbd>CTRL</kbd>).
If you really want both keys to have their own functionality, but different functionality when both are pressed "at the same time", then your only option is to implement a delay in handling the press of a single key, waiting to see if the other key is pressed before that delay expires. This, of course, comes at the expense of responsiveness.
Here's an implementation of that, using a short (25ms) PauseTransition
for the delay. (I also changed to use an ObservableSet
, which cleans up some of the logic.)
private ObservableSet<KeyCode> keys = FXCollections.observableSet();
private PauseTransition keyDelay = new PauseTransition(Duration.millis(25));
private void keyboardShortcuts(Scene scene){
// collect pressed key
scene.addEventFilter(KeyEvent.KEY_PRESSED, (e) -> {
keys.add(e.getCode());
e.consume();
});
// remove pressed key when it is released
scene.setOnKeyReleased((e) -> {
keys.remove(e.getCode());
e.consume();
});
keys.addListener((Change<? extends KeyCode> c) -> {
if (keys.size() <= 1) {
keyDelay.playFromStart();
} else {
keyDelay.stop();
checkKeys();
}
});
keyDelay.setOnFinished(e -> checkKeys());
}
private void checkKeys() {
if(keys.contains(KeyCode.A) && keys.contains(KeyCode.B)) {
System.out.println("A and B");
} else if(keys.contains(KeyCode.A)) {
System.out.println("A only");
} else if(keys.contains(KeyCode.B)) {
System.out.println("B only");
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论