代码之家  ›  专栏  ›  技术社区  ›  Tania

这是javafx中事件过滤器和requstfocus的正确行为吗?

  •  1
  • Tania  · 技术社区  · 6 年前

    我有一个非常简单的任务要完成。我只想按下按钮上的任何字母,匹配键代码,然后将焦点移动到文本字段。我写道 一个简单的测试代码,如图所示。我可以转移注意力。然而 我不希望我按下的字母显示在文本字段中。看似简单的编程解决方案其实并不那么简单。

    我不明白为什么event consume方法不能阻止事件沿着事件链传播,并在文本字段中显示键入的字母。

    似乎在调用requestFocus之后,文本字段会拾取从按钮键入的字母。这在Mac上发生。任何帮助都将不胜感激。

    package testkeynavigation;
    
    
    public class TestKeyNavigation extends Application {
    
    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
    
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });
    
        StackPane root = new StackPane();
    
        TextField txt1 = new TextField();
        TextField txt2 = new TextField();
        VBox vbox = new VBox();
        vbox.getChildren().add(btn);
        vbox.getChildren().add(txt1);
        vbox.getChildren().add(txt2);
        root.getChildren().add(vbox);
    
        Scene scene = new Scene(root, 300, 250);
    
    
        btn.setOnKeyPressed((KeyEvent e) ->{
            if (e.getCode() == KeyCode.A) {
                e.consume();
                System.out.println("e.isConsumed: "+e.isConsumed());
                txt2.requestFocus();
            }
    
        });
    
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    
        btn.requestFocus();
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    
    }
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   James_D    6 年前

    关键事件有三种: KEY_PRESSED ,则, KEY_TYPED KEY_RELEASED 。在按键笔划中,每种类型的事件都会按顺序激发到事件发生时具有键盘焦点的UI节点。

    A. TextField 具有内部侦听器 键入KEY\u 事件;所以如果 键入KEY\u 事件发生在文本字段具有焦点、在文本字段中输入字符(或发生其他操作,例如删除字符或移动插入符号,具体取决于键)时。

    在您的代码中,您将侦听其中的第一个- 按键\u已按下 -发生在按钮上。如果按键的代码为 A ,您消费 那个 事件(the 按键\u已按下 事件),然后将键盘焦点转移到文本字段。稍后,用户释放键,由于文本字段现在具有焦点,因此 键入KEY\u 事件在文本字段上激发。请注意,这是一个新事件,因此它不会被使用,因此文本字段的反应就像输入了字符一样。最后,a KEY\u已释放 事件在文本字段上激发。

    如果添加调试代码,则可以看到此操作:

    txt2.addEventFilter(KeyEvent.ANY, e -> {
        System.out.printf("Key event on text field: type=%s, code=%s, character=%s%n", 
                e.getEventType(), e.getCode(), e.getCharacter());
    });
    

    要解决此问题,只需侦听一系列事件中的最后一个事件:key released事件。请注意,您不需要使用该事件。

    public void start(Stage primaryStage) {
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
    
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });
    
        StackPane root = new StackPane();
    
        TextField txt1 = new TextField();
        TextField txt2 = new TextField();
        VBox vbox = new VBox();
        vbox.getChildren().add(btn);
        vbox.getChildren().add(txt1);
        vbox.getChildren().add(txt2);
        root.getChildren().add(vbox);
    
        Scene scene = new Scene(root, 300, 250);
    
    
        btn.setOnKeyReleased((KeyEvent e) ->{
            if (e.getCode() == KeyCode.A) {
                txt2.requestFocus();
            }
    
        });
    
        txt2.addEventFilter(KeyEvent.ANY, e -> {
            System.out.printf("Key event on text field: type=%s, code=%s, character=%s%n", 
                    e.getEventType(), e.getCode(), e.getCharacter());
        });
    
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    
        btn.requestFocus();
    }