JEditorPaneHTMLEditorKitParserMethodCancelled取消键

wen java案例 4

本文目录导读:

JEditorPaneHTMLEditorKitParserMethodCancelled取消键

  1. 常见原因
  2. 解决方案
  3. 终极方案:使用 JEditorPane 的替代品
  4. 总结建议

在 Java 的 JEditorPane 中使用 HTMLEditorKit 解析 HTML 时,遇到 “ParserMethodCancelled” (解析方法被取消) 错误,通常是因为解析过程被中断触发了意外的取消操作

以下是常见原因及解决方案:


常见原因

  • 用户按下了取消键(ESC)或调用了 DocumentParser.parse() 的取消方法。
  • 并发修改:在解析过程中动态修改了文档内容。
  • 调用 setText() 过于频繁:在短时间内多次调用 setText() 导致前一次解析被取消。
  • 使用了不兼容的 HTML 标签或格式:极少情况下,畸形 HTML 可能导致解析器内部触发取消。
  • 调用 getDocument() 的异步操作:在事件分派线程(EDT)之外操作文档。

解决方案

避免在 EDT 中频繁调用 setText()

最常见的原因是连续多次调用 setText(),确保一次只设置一次内容:

// 错误示例
editorPane.setText("<html><body>Loading...</body></html>");
// 稍后立即又设置新内容(可能在前一次解析未完成时)
editorPane.setText("<html><body>" + longData + "</body></html>");

改进:先设置初始文本,等数据准备好后,使用 SwingUtilities.invokeLater() 延迟设置:

SwingUtilities.invokeLater(() -> {
    editorPane.setText(fullHtml);
});

或使用 Document 对象的 replace() 方法而不是 setText()

禁用自动取消(推荐)

直接替换 HTMLEditorKit 的解析器,关闭取消检测:

import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
JEditorPane editorPane = new JEditorPane();
editorPane.setContentType("text/html");
// 获取当前 HTMLEditorKit
HTMLEditorKit kit = (HTMLEditorKit) editorPane.getEditorKit();
// 创建一个新的解析器,重写取消逻辑
ParserDelegator delegator = new ParserDelegator() {
    @Override
    public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet) throws IOException {
        // 创建自定义的 DocumentParser,禁用取消功能
        super.parse(r, new HTMLEditorKit.ParserCallback() {
            // 所有回调直接委托给原始 callback
            @Override
            public void handleText(char[] data, int pos) { cb.handleText(data, pos); }
            @Override
            public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) { cb.handleStartTag(t, a, pos); }
            @Override
            public void handleEndTag(HTML.Tag t, int pos) { cb.handleEndTag(t, pos); }
            // ... 其他必要回调 ...
            @Override
            public void handleComment(char[] data, int pos) { cb.handleComment(data, pos); }
            @Override
            public void handleError(String errorMsg, int pos) { cb.handleError(errorMsg, pos); }
            @Override
            public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) { cb.handleSimpleTag(t, a, pos); }
            @Override
            public void handleEndOfLineString(String eol) { /* 忽略 */ }
            @Override
            public void flush() throws BadLocationException { cb.flush(); }
        }, ignoreCharSet);
    }
};
// 设置到 EditorKit
kit.setParser(delegator);

注意:此方案会完全忽略取消请求,适用于确定不会死循环的 HTML。

使用 SwingWorker 加载 HTML

将耗时的 HTML 加载放到后台线程,避免 EDT 阻塞:

SwingWorker<String, Void> worker = new SwingWorker<>() {
    @Override
    protected String doInBackground() throws Exception {
        // 从文件/网络加载 HTML(不要在 EDT 中做)
        return loadHtmlFromSource();
    }
    @Override
    protected void done() {
        try {
            String html = get();
            editorPane.setText(html);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
};
worker.execute();

捕获并忽略该异常

如果偶尔出现且不影响功能,可以直接捕获:

try {
    editorPane.setText(htmlContent);
} catch (Throwable t) {
    // 忽略 ParserMethodCancelled 异常
    if (!t.getMessage().contains("ParserMethodCancelled")) {
        t.printStackTrace();
    }
}

终极方案:使用 JEditorPane 的替代品

JEditorPane 的 HTML 渲染能力有限且老旧,如果需要稳定显示复杂 HTML,建议迁移到:

  • JavaFX WebView(推荐,Java 8+ 支持)
  • Flying Saucer (XHTMLRenderer) 纯 Java 渲染
  • JDK 9+ 的 javafx.scene.web.WebView

示例(JavaFX):

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.web.WebView;
JFXPanel jfxPanel = new JFXPanel();
Platform.runLater(() -> {
    WebView webView = new WebView();
    webView.getEngine().loadContent(htmlContent);
    jfxPanel.setScene(new Scene(webView));
});

总结建议

场景 推荐方案
偶尔出现,不影响使用 捕获异常
频繁触发,用户操作导致 重写解析器禁用取消
异步加载数据 SwingWorker
未来项目 / 复杂 HTML 使用 JavaFX WebView

最常见的成功做法是方案二(重写解析器)或确保在 EDT 中一次性设置文本

上一篇JEditorPaneHTMLEditorKitParserMethodIllegalSelector非法选择

下一篇当前分类已是最新一篇

抱歉,评论功能暂时关闭!