在 JavaFX 中检测单键按下
Detect single key press in JavaFX
我在检测 JavaFX 中的单键按下时遇到问题。我必须检测箭头键,但每次我按下这些键中的任何一个时,我的代码部分都会被多次调用。我意识到这是因为 AnimationTimer()
是一个循环,所以这就是原因,但我不知道如何检测单键点击。无论如何,这是代码:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.HashSet;
public class Main extends Application {
Stage window;
static Scene scene;
private static char[][] mapa = {
{'X','X','X','X','X'},
{'X','.','.','.','X'},
{'X','.','M','.','X'},
{'X','.','.','.','X'},
{'X','X','X','X','X'}
};
private final int sizeX = 16;
private final int sizeY = 16;
static HashSet<String> currentlyActiveKeys;
@Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Hello World");
Group root = new Group();
scene = new Scene(root);
window.setScene(scene);
Canvas canvas = new Canvas(512 - 64, 256);
root.getChildren().add(canvas);
prepareActionHandlers();
GraphicsContext gc = canvas.getGraphicsContext2D();
new AnimationTimer() {
@Override
public void handle(long now) {
gc.clearRect(0,0,512,512);
for(int i = 0; i < mapa.length; i++) {
for(int j = 0; j < mapa[i].length; j++) {
if(mapa[i][j] == 'X') {
gc.setLineWidth(5);
gc.setFill(Color.RED);
gc.fillRect(sizeX + i*sizeX, sizeY + j*sizeY, sizeX, sizeY);
} else if(mapa[i][j] == '.') {
gc.setLineWidth(5);
gc.setFill(Color.GREEN);
gc.fillRect(sizeX + i*sizeX, sizeY + j*sizeY, sizeX, sizeY);
} else if(mapa[i][j] == 'M') {
gc.setLineWidth(5);
gc.setFill(Color.BLACK);
gc.fillRect(sizeX + i*sizeX, sizeY + j*sizeY, sizeX, sizeY);
}
}
}
if(currentlyActiveKeys.contains("LEFT")) {
System.out.println("left");
}
if(currentlyActiveKeys.contains("RIGHT")) {
System.out.println("right");
}
if(currentlyActiveKeys.contains("UP")) {
System.out.println("up");
}
if(currentlyActiveKeys.contains("DOWN")) {
System.out.println("down");
}
}
}.start();
window.show();
}
private static void prepareActionHandlers()
{
currentlyActiveKeys = new HashSet<String>();
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event)
{
currentlyActiveKeys.add(event.getCode().toString());
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event)
{
currentlyActiveKeys.remove(event.getCode().toString());
}
});
}
public static void main(String[] args) {
launch(args);
}
}
当我按下箭头按钮时(当然其他键也是如此),在范围内我得到如下结果:
down
down
down
down
down
down
显然只要我按下按钮就会发生这种情况。一旦我停止按下它,打印就结束了。我想要实现的是,一旦我按下一个按钮(无论我按住它多久),我都会得到 down
一次。我需要这个,因为我想更新 canvas
.
中矩形的颜色
您可以声明一个全局布尔值并将其切换为 press = !press。然后每 2 秒将其重置为 true 或类似的东西。
if(currentlyActiveKeys.contains("DOWN") && press) {
press = !press;//sets it false
System.out.println("down");
}
发生的事情是 OS 具有一种自动键入功能,这样当您按住某个键时,它会不断生成按键事件,即使您并没有真正按下该键不止一次。
通过添加按键和按键释放处理程序以及每个键的布尔状态,您可以跟踪自按下键后是否处理过该键。然后,只要释放键,您就可以重置已处理的状态,以便下次真正按下时可以处理它。
示例应用程序
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.util.HashMap;
public class Main extends Application {
private HashMap<String, Boolean> currentlyActiveKeys = new HashMap<>();
@Override
public void start(Stage stage) throws Exception {
final Scene scene = new Scene(new Group(), 100, 100);
stage.setScene(scene);
scene.setOnKeyPressed(event -> {
String codeString = event.getCode().toString();
if (!currentlyActiveKeys.containsKey(codeString)) {
currentlyActiveKeys.put(codeString, true);
}
});
scene.setOnKeyReleased(event ->
currentlyActiveKeys.remove(event.getCode().toString())
);
new AnimationTimer() {
@Override
public void handle(long now) {
if (removeActiveKey("LEFT")) {
System.out.println("left");
}
if (removeActiveKey("RIGHT")) {
System.out.println("right");
}
if (removeActiveKey("UP")) {
System.out.println("up");
}
if (removeActiveKey("DOWN")) {
System.out.println("down");
}
}
}.start();
stage.show();
}
private boolean removeActiveKey(String codeString) {
Boolean isActive = currentlyActiveKeys.get(codeString);
if (isActive != null && isActive) {
currentlyActiveKeys.put(codeString, false);
return true;
} else {
return false;
}
}
public static void main(String[] args) {
launch(args);
}
}
我知道这已经是一个老问题了。经过数小时的努力,我只想分享我的发现。我终于找到了一个简单的解决方案,即添加 clear 函数。这就是我的意思
if(currentlyActiveKeys.contains("LEFT")) {
System.out.println("left");
}
if(currentlyActiveKeys.contains("RIGHT")) {
System.out.println("right");
}
if(currentlyActiveKeys.contains("UP")) {
System.out.println("up");
}
if(currentlyActiveKeys.contains("DOWN")) {
System.out.println("down");
}
currentlyActiveKeys.clear();
这最后一行将清除当前活动的密钥,从而防止重复post
我在检测 JavaFX 中的单键按下时遇到问题。我必须检测箭头键,但每次我按下这些键中的任何一个时,我的代码部分都会被多次调用。我意识到这是因为 AnimationTimer()
是一个循环,所以这就是原因,但我不知道如何检测单键点击。无论如何,这是代码:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.HashSet;
public class Main extends Application {
Stage window;
static Scene scene;
private static char[][] mapa = {
{'X','X','X','X','X'},
{'X','.','.','.','X'},
{'X','.','M','.','X'},
{'X','.','.','.','X'},
{'X','X','X','X','X'}
};
private final int sizeX = 16;
private final int sizeY = 16;
static HashSet<String> currentlyActiveKeys;
@Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Hello World");
Group root = new Group();
scene = new Scene(root);
window.setScene(scene);
Canvas canvas = new Canvas(512 - 64, 256);
root.getChildren().add(canvas);
prepareActionHandlers();
GraphicsContext gc = canvas.getGraphicsContext2D();
new AnimationTimer() {
@Override
public void handle(long now) {
gc.clearRect(0,0,512,512);
for(int i = 0; i < mapa.length; i++) {
for(int j = 0; j < mapa[i].length; j++) {
if(mapa[i][j] == 'X') {
gc.setLineWidth(5);
gc.setFill(Color.RED);
gc.fillRect(sizeX + i*sizeX, sizeY + j*sizeY, sizeX, sizeY);
} else if(mapa[i][j] == '.') {
gc.setLineWidth(5);
gc.setFill(Color.GREEN);
gc.fillRect(sizeX + i*sizeX, sizeY + j*sizeY, sizeX, sizeY);
} else if(mapa[i][j] == 'M') {
gc.setLineWidth(5);
gc.setFill(Color.BLACK);
gc.fillRect(sizeX + i*sizeX, sizeY + j*sizeY, sizeX, sizeY);
}
}
}
if(currentlyActiveKeys.contains("LEFT")) {
System.out.println("left");
}
if(currentlyActiveKeys.contains("RIGHT")) {
System.out.println("right");
}
if(currentlyActiveKeys.contains("UP")) {
System.out.println("up");
}
if(currentlyActiveKeys.contains("DOWN")) {
System.out.println("down");
}
}
}.start();
window.show();
}
private static void prepareActionHandlers()
{
currentlyActiveKeys = new HashSet<String>();
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event)
{
currentlyActiveKeys.add(event.getCode().toString());
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event)
{
currentlyActiveKeys.remove(event.getCode().toString());
}
});
}
public static void main(String[] args) {
launch(args);
}
}
当我按下箭头按钮时(当然其他键也是如此),在范围内我得到如下结果:
down
down
down
down
down
down
显然只要我按下按钮就会发生这种情况。一旦我停止按下它,打印就结束了。我想要实现的是,一旦我按下一个按钮(无论我按住它多久),我都会得到 down
一次。我需要这个,因为我想更新 canvas
.
您可以声明一个全局布尔值并将其切换为 press = !press。然后每 2 秒将其重置为 true 或类似的东西。
if(currentlyActiveKeys.contains("DOWN") && press) {
press = !press;//sets it false
System.out.println("down");
}
发生的事情是 OS 具有一种自动键入功能,这样当您按住某个键时,它会不断生成按键事件,即使您并没有真正按下该键不止一次。
通过添加按键和按键释放处理程序以及每个键的布尔状态,您可以跟踪自按下键后是否处理过该键。然后,只要释放键,您就可以重置已处理的状态,以便下次真正按下时可以处理它。
示例应用程序
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.util.HashMap;
public class Main extends Application {
private HashMap<String, Boolean> currentlyActiveKeys = new HashMap<>();
@Override
public void start(Stage stage) throws Exception {
final Scene scene = new Scene(new Group(), 100, 100);
stage.setScene(scene);
scene.setOnKeyPressed(event -> {
String codeString = event.getCode().toString();
if (!currentlyActiveKeys.containsKey(codeString)) {
currentlyActiveKeys.put(codeString, true);
}
});
scene.setOnKeyReleased(event ->
currentlyActiveKeys.remove(event.getCode().toString())
);
new AnimationTimer() {
@Override
public void handle(long now) {
if (removeActiveKey("LEFT")) {
System.out.println("left");
}
if (removeActiveKey("RIGHT")) {
System.out.println("right");
}
if (removeActiveKey("UP")) {
System.out.println("up");
}
if (removeActiveKey("DOWN")) {
System.out.println("down");
}
}
}.start();
stage.show();
}
private boolean removeActiveKey(String codeString) {
Boolean isActive = currentlyActiveKeys.get(codeString);
if (isActive != null && isActive) {
currentlyActiveKeys.put(codeString, false);
return true;
} else {
return false;
}
}
public static void main(String[] args) {
launch(args);
}
}
我知道这已经是一个老问题了。经过数小时的努力,我只想分享我的发现。我终于找到了一个简单的解决方案,即添加 clear 函数。这就是我的意思
if(currentlyActiveKeys.contains("LEFT")) {
System.out.println("left");
}
if(currentlyActiveKeys.contains("RIGHT")) {
System.out.println("right");
}
if(currentlyActiveKeys.contains("UP")) {
System.out.println("up");
}
if(currentlyActiveKeys.contains("DOWN")) {
System.out.println("down");
}
currentlyActiveKeys.clear();
这最后一行将清除当前活动的密钥,从而防止重复post