您需要使用filter,而不是handler。
这是一个演示此功能的示例应用程序:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.web.HTMLEditor;
import javafx.stage.Stage;
public class EventCapture extends Application {
@Override
public void start(final Stage stage) {
HTMLEditor editor = new HTMLEditor();
editor.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.isMetaDown() && KeyCode.Z.equals(event.getCode())) {
event.consume();
System.out.println("consumed event = " + event);
}
});
stage.setScene(new Scene(editor));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
上面的代码是在带有 Java 和 JavaFX 16 的 Mac 上使用 HTMLEditor 测试的。这会拦截 Mac 上的默认撤消组合键 (Command + Z) 并忽略它,从而阻止它被路由到底层 HTMLEditor 实现(其中基于WebView)。这实际上禁用了基于键的加速器以用于编辑器的撤消功能。对于非 Mac PC(例如 Windows PC),您可能需要截取不同的组合键。
我发现(通过实验)在 Mac 上触发撤消功能的事件是 KEY_PRESSED 事件(而不是 KEY_TYPED 或 KEY_RELEASED 事件),所以这是我选择使用的事件。
为了更好地理解这一点,请阅读 Oracle 的(优秀的)tutorial on event handling,我要求他们写,他们欣然同意这样做。特别是,查看event filters 和event capturing phase 部分。链接文档将解释事件捕获阶段(应用过滤器时)和事件冒泡阶段(应用处理程序时)之间的区别,这对于理解此问题的解决方案至关重要。
事件过滤器部分是这样描述它们的:
事件过滤器通常用于事件调度链的分支节点,并在事件处理的事件捕获阶段被调用。使用过滤器执行操作,例如覆盖事件响应或阻止事件到达其目的地。
这正是你想要的。
稍微跑题:事件调试提示
要显示在捕获阶段写入期间发送到节点的所有事件:
editor.addEventFilter(EventType.ROOT, System.out::println);
显示在冒泡阶段发送到节点的所有事件写入:
editor.addEventHandler(EventType.ROOT, System.out::println);
其他问题的答案
如果你删除 event.isMetaDown() 条件让它只是'z',然后运行程序并输入'z','z' 不会被消耗,并且仍然出现在编辑器中,怎么办?
因为当KEY_TYPED 事件发生时,“z”出现在编辑器中,并且过滤器被写入仅过滤KEY_PRESSED 事件。
如果您想过滤“z”类型,请更改被过滤的事件类型。
如果您只想过滤小写类型的“z”(而不是大写),则只使用匹配字符的 KEY_TYPED 事件。
editor.addEventFilter(KeyEvent.KEY_TYPED, event -> {
if ("z".equals(event.getCharacter())) {
event.consume();
}
});