这对于javafx中的事件过滤器和requstfocus是正确的行为吗? [英] Is this the proper behaviour for event filter and requstfocus in javafx?
问题描述
我有一个非常简单的任务要完成.我只想按按钮上的任何字母,匹配键代码,然后将焦点移到文本字段.我写 如图所示的简单测试代码.我没问题转移重点.然而, 我不希望我按的字母显示在文本字段中.看来,一个简单的编程解决方案并不是那么简单.
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_PRESSED
,KEY_TYPED
和KEY_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屋!