在JavaFX中检测单键按下 [英] Detect single key press in JavaFX

查看:163
本文介绍了在JavaFX中检测单键按下的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了在JavaFX中检测单键按下的问题。我必须检测箭头键,但每次按下任何一个键时,我的代码的一部分被多次调用。我意识到这是因为 AnimationTimer()是一个循环因此这是原因,但我不知道如何检测单键敲击。无论如何,这里是代码:

I have a problem of detecting a single key press in JavaFX. I have to detect arrow keys but each time I press any of those keys part of my code is being called multiple times. I realize that it is because AnimationTimer() is a loop thus this is the reason but I have no idea how to detect single key tap. Anyways, here is the code:

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);
    }
}

当我按下箭头按钮时(与其他相同)当然),在范围内我得到的结果如下:

When I press down arrow button (same goes with other keys of course), in the scope I am getting results like:

down
down
down
down
down
down

显然只要我发生这种情况按下按钮。一旦我停止按下它,打印结束。我想要实现的是,一旦我按下一个按钮(无论我持有多长时间),我只需要一次向下。我需要这个,因为我想在 canvas 中更新我的矩形的颜色。

Obviously this happens as long as I press the button. Once I stop pressing it, printing ends. What I would love to achieve is that once I press a button (no matter how long I hold it) I will get down just once. I need this because I would like to update the color of my rectangles in the canvas.

推荐答案

正在发生的事情是操作系统有一种自动输入功能,这样当你按住一个键时,它会不断产生按键事件,即使你不是真的按键不止一次。

What is happening is that the OS has a kind of automatic typing function, such that when you hold a key down, it keeps generating key press events, even though you aren't really pressing the key more than once.

通过为每个键添加按键和键释放处理程序以及布尔状态,您可以跟踪自按键以来是否已处理该键。然后,只要释放该键,就可以重置该处理状态,以便下次真正按下它时可以处理它。

By adding both key press and key release handlers and a boolean state for each key, you can keep track of whether you have processed the key since it was pressed. You can then reset that processed state whenever the key is released so that the next time it is really pressed you can handle it.

示例应用程序

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);
    }
}

这篇关于在JavaFX中检测单键按下的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆