检测JavaFX中的单键按下

 2023-02-17    393  

问题描述

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

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

检测JavaFX中的单键按下

down
down
down
down
down
down

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

推荐答案

发生的事情是,操作系统具有一种自动键入功能,因此当您按住钥匙时,它会继续生成密钥按下事件,即使您并没有真正按下键.

通过为每个键添加密钥按下和键发布处理程序和布尔态状态,您可以跟踪自按下键以来是否已经处理过该键.然后,您可以每当释放键时重置该处理状态

示例应用程序

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

其他推荐答案

您可以声明全局布尔值,并像press =!press一样.然后每2秒钟将其重置为true或某种效果.

if(currentlyActiveKeys.contains("DOWN") && press) {
       press = !press;//sets it false
       System.out.println("down");
 }

其他推荐答案

我知道这已经是一个长期的问题.我只是想分享我的发现几个小时的挣扎.我终于找到了一个简单的解决方案,即通过添加清晰的功能.这是我的意思

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

这最后一行将清除当前有效的密钥,因此它将阻止重复,如原始帖子

中所述

以上所述是小编给大家介绍的检测JavaFX中的单键按下,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/34135.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。