【问题标题】:JavaFX KeyEvent.consume() Fails to Stop Event PropagationJavaFX KeyEvent.consume() 无法停止事件传播
【发布时间】:2021-09-19 17:16:47
【问题描述】:

我正在尝试在 JavaFX 中重现 JavaScript 游戏的某些行为。该程序有几个数字文本字段,可以在游戏运行时进行编辑。它还在运行时接受字母键盘命令。

在我的版本中,我尝试捕获、响应和删除键盘命令,即使其中一个数字文本字段被聚焦。我认为使用EventFilter 应该可以工作——在处理事件的捕获阶段,在键盘事件到达TextFields 之前使用它们。但到目前为止,我还无法阻止字母键盘输入到达文本字段。

这是一个 SSCCE,它说明了我已经尝试过什么以及什么不起作用。

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class KeyFilterSSCCE extends Application {

    @Override
    public void start(Stage stage) {
        stage.setTitle("Key Filter SSCCE");
        TextField tf = new TextField("XYZ abc");
        tf.setMaxWidth(150);
        Label label = new Label("Filtered Keys: ");
        VBox root = new VBox(20, tf, label);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(20));
        Scene scene = new Scene(root, 325, 200);

        stage.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
            if (e.getCode() == KeyCode.S) {
                label.setText(label.getText() + e.getCode().getChar());
                e.consume();
            }
        });

        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}

该程序应允许您在文本字段中键入并在“S”字符输入字段之前捕获并删除它们。代码显示“S”字符被正确检测到,但它们仍然显示在文本字段中,即使在consume()ed 之后也是如此。

在调用consume() 之后,isConsumed() 方法确认事件被正确标记为已消费,但调度链没有像documentation 指示的那样短路。

我已尝试将事件过滤器添加到路径中的其他 Nodes 到文本字段,但行为没有变化。我已经尝试过滤KeyEvent.ANYKeyEvent.KEY_TYPEDKeyEvent.KEY_RELEASED 而不改变行为。我已经看到这个similar question 的答案提出了类似于我正在尝试的内容。

我是否误解了这应该如何工作?

由于实际程序中的所有TextFields 都附加了TextFormatters,我想我可以在格式化程序中添加一个过滤功能来拒绝键盘命令字符。不过,这似乎是一种迂回的做法。

macOS、Java 17、JavaFX 17,如果这有什么不同的话。

【问题讨论】:

  • 这听起来像是一个用例,您应该使用TextFormatter 而不是EventFilter。由于我使用EventFilterTextFormatter 的经验有限,我可能会错。
  • 这是我尝试找出使用哪一个时的思路。如果您要对TextField 中的文本进行任何操作,请使用TextFormatter。如果不是,请使用EventFilter。这是一个很好的例子:courses.bekwam.net/public_tutorials/bkcourse_visualcueapp.html.
  • 使用过滤器中输入的内容
  • .. 澄清我的夜间评论:代码显示'S'字符被正确检测,但它们仍然显示在文本字段中难怪,它被插入通过 keyTyped (与您使用的 keyPressed 相比)。解决方案是在过滤器中使用keyTyped。
  • @kleopatra,谢谢。在你的帮助下,我想出了一个有效的过滤器。

标签: java javafx


【解决方案1】:

在@kleopatras 评论和更多实验之后,这是一个按预期运行的事件过滤器版本:

    stage.addEventFilter(KeyEvent.KEY_TYPED, e -> {
        if (e.getCharacter().toUpperCase().equals("S")) {
            label.setText(label.getText() + e.getCharacter());
            e.consume();
        }
    });

过滤KeyEvent.KEY_TYPED 事件是我所需要的。此外,由于该事件的事件getCode() 方法返回UNDEFINED,因此必须稍微修改测试以针对getCharacter() 的结果进行测试,奇怪的是,它返回String

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 2011-01-05
    • 2012-10-10
    • 2011-04-06
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多