这对于javafx中的事件过滤器和requstfocus是正确的行为吗? [英] Is this the proper behaviour for event filter and requstfocus in javafx?

查看:167
本文介绍了这对于javafx中的事件过滤器和requstfocus是正确的行为吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的任务要完成.我只想按按钮上的任何字母,匹配键代码,然后将焦点移到文本字段.我写 如图所示的简单测试代码.我没问题转移重点.然而, 我不希望我按的字母显示在文本字段中.看来,一个简单的编程解决方案并不是那么简单.

I have a very simple task to accomplish. I just want to press any letter on a button, matches the key code, and move the focus to a text field. I wrote a simple test code as shown. I have no problem to shift the focus. However, I don't want the letter I press shows up in the text field. Seemingly a simple programming solution turns out to be not so simple.

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

I don't understand why the event consume method doesn't stop the event from propagating down the event chain and have the typed letter shown up at the text field.

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

It seems like after the requestFocus is called, the text field picks up the letter typed from the button. This happens on Mac. Any help will be greatly appreciated.

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

}

推荐答案

有三种键事件:KEY_PRESSEDKEY_TYPEDKEY_RELEASED.在击键操作中,每种类型的事件都会按此顺序触发到在事件发生时具有键盘焦点的UI节点.

There are three kinds of key event: KEY_PRESSED, KEY_TYPED, and KEY_RELEASED. In a key stroke, an event of each of these types is fired, in that order, to the UI node that has the keyboard focus at the time of the event.

TextField具有用于KEY_TYPED事件的内部侦听器;因此,如果在文本字段具有焦点时发生KEY_TYPED事件,则会在文本字段中输入一个字符(或发生其他操作,例如,根据键,删除字符或移动插入符号).

A TextField has an internal listener for KEY_TYPED events; so if a KEY_TYPED event occurs when the text field has focus, a character is entered into the text field (or other actions occur, e.g. deleting characters or moving the caret, depending on the key).

在您的代码中,您将监听其中的第一个-KEY_PRESSED-出现在按钮上.如果按键的代码为A,则消耗 that 事件(KEY_PRESSED事件),然后将键盘焦点转移到文本字段.稍后,用户释放键,并且由于文本字段现在具有焦点,因此会在文本字段上触发KEY_TYPED事件.请注意,这是一个新事件,因此不会被使用,因此文本字段的反应就像输入了字符一样.最后,在文本字段上触发一个KEY_RELEASED事件.

In your code, you listen for the first one of these - KEY_PRESSED - to occur on the button. If the key press has a code of A, you consume that event (the KEY_PRESSED event) then transfer keyboard focus to the text field. At a slightly later moment, the user releases the key, and since the text field now has focus, a KEY_TYPED event is fired on the text field. Note that this is a new event, so it is not consumed, so the text fields reacts as though a character has been entered. Finally, a KEY_RELEASED event is fired on the text field.

如果添加调试代码,您可以看到它的作用:

You can see this in action if you add the debugging code:

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

要解决此问题,只需侦听一系列事件中的最后一个事件:按键释放事件.请注意,您不需要使用该事件.

To fix the problem, just listen for the last event in the series of events: the key released event. Note that you don't need to consume the event.

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

这篇关于这对于javafx中的事件过滤器和requstfocus是正确的行为吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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