JavaFX KeyEvent 不执行任何操作

JavaFX KeyEvent doesn't do anything

所以我有一个小程序,你可以在行星之间驾驶你的宇宙飞船,我想用箭头键来旋转飞船。首先,我尝试将关键侦听器添加到面板,飞船确实旋转了,但只有在我按下 ctrl/alt 时才会旋转。然后我尝试将关键侦听器添加到场景中(人们说这是正确的做法,因为它不依赖于焦点),但是尽管调用了旋转船的功能,但您看不到任何东西屏幕。

主要class:

@Override
public void start(Stage stage) {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
        Parent root = loader.load();
        Scene scene = new Scene(root, 700, 500);
        Controller controller = new Controller();
        loader.setController(controller);
             
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        stage.setScene(scene);
        stage.setFullScreen(true);
        stage.show();
        controller.setScene(scene);
    } catch(Exception e) {
        e.printStackTrace();
    }
        
} 

控制器:

    @FXML
    private BorderPane contentPane;
    
    private OrbiterPanel orbiterPanel = new PerfectCirclePanel(this);
    private Scene scene;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        contentPane.setCenter(orbiterPanel);
    }

    public void setScene(Scene scene) {
        this.scene = scene;
        scene.addEventFilter(KeyEvent.KEY_PRESSED, e -> keyStrokesPressed(e));
        scene.addEventFilter(KeyEvent.KEY_RELEASED, e -> keyStrokesReleased(e));
    } 
    
    private void keyStrokesPressed(KeyEvent e) {
        switch(e.getCode()) {
        case LEFT -> {
            orbiterPanel.leftPressed();
        }
        case RIGHT -> {
            orbiterPanel.rightPressed();
        }
        default -> {}
        }   
    }
    
    private void keyStrokesReleased(KeyEvent e) {
        switch(e.getCode()) {
        case LEFT -> {
            orbiterPanel.leftReleased();
        }
        case RIGHT -> {
            orbiterPanel.rightReleased();
        }
        default -> {}
        }
    } 

我所有“worlds/maps”的超级class:

protected AtomicReference<Spaceship> shipReference = new AtomicReference<>();
    
    protected RotateTransition rotatingTransition;
    
    public OrbiterPanel() {
        rotatingTransition = new RotateTransition();
        rotatingTransition.setCycleCount(RotateTransition.INDEFINITE);
        rotatingTransition.setInterpolator(Interpolator.LINEAR);
    }
    
    protected void rightPressed() {
        if(rotatingTransition.getStatus().equals(Status.RUNNING)) return;
        rotatingTransition.stop();
        rotatingTransition.setNode(shipReference.get());
        rotatingTransition.setByAngle(360);
        rotatingTransition.setDuration(Duration.seconds(2));
        rotatingTransition.play();
    }
    
    protected void leftPressed() {
        if(rotatingTransition.getStatus().equals(Status.RUNNING)) return;
        rotatingTransition.stop();
        rotatingTransition.setNode(shipReference.get());
        rotatingTransition.setByAngle(-360);
        rotatingTransition.setDuration(Duration.seconds(2));
        rotatingTransition.play();
    }
    
    protected void rightReleased() {
        rotatingTransition.stop();
    }
    
    protected void leftReleased() {
        rotatingTransition.stop();
    } 

PerfectCirclePanel,OrbiterPanel 的一个子class,除了显示宇宙飞船和行星外,并没有做太多事情。 FXML:

<BorderPane prefHeight="607.0" prefWidth="877.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
   <center>
      <BorderPane fx:id="contentPane" prefHeight="704.0" prefWidth="963.0" style="-fx-background-color: black;">
      </BorderPane>
   </center>
</BorderPane>

有两种不同的方法可以将控制器连接到 FXML 文件定义的 UI。

任一:

  1. 通过向 FXML 的根元素提供 fx:controller 属性来指定控制器 class。在这种情况下,默认情况下,控制器实例将通过调用其无参数构造函数从 class 创建,并且该实例将是与 UI.
  2. 关联的控制器

:

  1. FXMLLoader 实例上调用 setController(...)

当你调用loader.load()时,如果控制器存在,控制器中的任何@FXML注解字段将从相应的FXML元素初始化,然后initialize()方法将被调用。

在您的代码中,您创建了两个 Controller 实例:一个是从 fx:controller 属性创建的,并与 UI 相关联。另一个是您在 Java 代码中“手动”创建的。后者未连接到 UI(未注入 @FXML-注释字段,并且未调用 initialize()),因为您调用 setController(...) 调用 load().

之后

因为有两个Controller实例,所以有两个OrbiterPanel实例。从 fx:controller 属性创建的那个是显示在 UI 中的那个(因为这是调用 initialize() 时引用的那个)。不显示从您在代码中创建的 Controller 实例创建的;然而,这是您的事件处理程序引用的那个。

删除 fx:controller 属性,并将调用移至 setController(),然后再调用 load()