【问题标题】:JavaFX HTMLEditor over-ride default typing behaviourJavaFX HTMLEditor 覆盖默认类型行为
【发布时间】:2021-08-26 22:15:42
【问题描述】:

我有一个带有以下对象的 JavaFX HTMLEditor:

HTMLEditor htmlEditor;
WebView webView;
WebEngine webEngine;
HTMLDocumentImpl htmlDocImpl;

我想要的是在用户按下 Ctrl+Z 时覆盖默认的撤消功能。我是一个编程新手,但我的理解是 HTMLEditor 没有我可以使用的撤消/重做功能(即使 Ctrl+Z 以某种方式撤消我输入的文本)

我有很多在编辑器中操作 HTML 的函数,所以我需要一个自定义的撤消函数。实现我自己的第一步是覆盖按 Ctrl+Z 时发生的情况

我似乎不知道该怎么做。例如,这段试图关闭所有打字功能的代码无效:

htmlEditor.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
    e.consume();
});
htmlEditor.addEventHandler(KeyEvent.KEY_RELEASED, e -> {
    e.consume();
});
htmlEditor.addEventHandler(KeyEvent.KEY_TYPED, e -> {
    e.consume();
});

我如何捕获特定按键,取消其默认功能,然后调用我自己的函数?

感谢您的帮助

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    您需要使用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 filtersevent 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();
        }
    });
    

    【讨论】:

    • 哇,感谢您的出色回答。我会阅读事件,但是如果你删除 event.isMetaDown() 条件,所以它只是'z',然后运行程序并输入'z','z' 不会被消耗并且仍然出现在编辑?再次感谢
    • 我更新了答案以回答您的其他问题。这些问题有些相关,但有时当答案与原始问题不同时,最好将其他问题作为新问题而不是 cmets 提出。
    猜你喜欢
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    相关资源
    最近更新 更多