本文目录导读:

看起来你遇到了 JEditorPane 与 HTMLEditorKit 在解析 HTML 时出现的 “Parser method cancelled” 错误,这通常与 取消(Cancel)键 或解析器被中断有关。
问题原因
JEditorPane 使用 HTMLEditorKit 解析 HTML 时,内部会启动一个 Parser 线程,当用户按下 Esc 键 或通过其他方式触发取消操作时,解析器可能会被中断,抛出类似 “Parser method cancelled” 的异常。
常见场景
- 用户按 Esc 键 - 中断了正在进行的 HTML 解析
- 更新时 - 旧的解析任务被取消,新任务开始
- 异步加载 - 在 SwingWorker 或后台线程中修改文档内容
解决方案
方案 1:捕获并忽略异常(推荐)
import javax.swing.*;
import javax.swing.text.html.*;
import java.awt.*;
public class HtmlEditorCancelFix extends JFrame {
public HtmlEditorCancelFix() {
JEditorPane editorPane = new JEditorPane();
editorPane.setContentType("text/html");
editorPane.setEditable(false);
// 关键:捕获异常,避免影响 GUI
// 可以通过自定义 HTMLEditorKit 来实现
editorPane.setEditorKit(new SafeHtmlEditorKit());
// 设置 HTML 内容
editorPane.setText("<html><body><h1>Hello World</h1>" +
"<p>Some long content that might trigger cancellation...</p></body></html>");
JScrollPane scrollPane = new JScrollPane(editorPane);
add(scrollPane, BorderLayout.CENTER);
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
// 自定义安全的 HTMLEditorKit
private static class SafeHtmlEditorKit extends HTMLEditorKit {
@Override
public Document createDefaultDocument() {
return new SafeHtmlDocument();
}
}
private static class SafeHtmlDocument extends HTMLDocument {
@Override
public void setParser(HtmlDocument.HTMLReader reader) {
try {
super.setParser(reader);
} catch (Exception e) {
// 忽略所有解析相关异常,包括 cancelled 异常
System.err.println("Parser cancelled ignored: " + e.getMessage());
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new HtmlEditorCancelFix().setVisible(true));
}
}
方案 2:禁用 Esc 键取消
如果你确认不需要取消功能,可以禁用 Esc 键:
// 在初始化时添加按键拦截
editorPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke("ESCAPE"), "none");
editorPane.getActionMap().put("none", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
// 不做任何操作
}
});
方案 3:使用代理模式包装解析器
更彻底的解决方案是重写 HTMLEditorKit 的解析器:
public class CancellationSafeHtmlEditorKit extends HTMLEditorKit {
@Override
public ViewFactory getViewFactory() {
return new HTMLFactory() {
@Override
public View create(Element elem) {
// 可以在创建 View 时添加保护
return super.create(elem);
}
};
}
@Override
public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {
try {
super.read(in, doc, pos);
} catch (Exception e) {
if (e.getMessage() != null &&
e.getMessage().contains("cancelled")) {
// 静默处理取消异常
return;
}
throw e; // 其他异常继续抛出
}
}
}
方案 4:使用 SwingUtilities.invokeLater
更新在 EDT(事件调度线程)中执行:
SwingUtilities.invokeLater(() -> {
try {
editorPane.setText(htmlContent);
} catch (Exception e) {
// 忽略 cancelled 异常
if (!e.getMessage().contains("cancelled")) {
e.printStackTrace();
}
}
});
完整示例:生产环境可用的解决方案
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import java.awt.*;
import java.io.*;
public class JEditorPaneCancellationFixDemo extends JFrame {
private JEditorPane editorPane;
public JEditorPaneCancellationFixDemo() {
setTitle("JEditorPane 取消异常处理");
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 使用自定义编辑器套件
editorPane = new JEditorPane();
editorPane.setEditorKit(new CancellationSafeKit());
editorPane.setEditable(false);
// 设置示例内容
editorPane.setText(loadExampleHtml());
JScrollPane scrollPane = new JScrollPane(editorPane);
add(scrollPane, BorderLayout.CENTER);
// 按钮演示:加载新内容可能触发取消
JButton loadButton = new JButton("加载复杂 HTML");
loadButton.addActionListener(e -> {
SwingUtilities.invokeLater(() -> {
editorPane.setText(generateComplexHtml());
});
});
add(loadButton, BorderLayout.SOUTH);
}
private String loadExampleHtml() {
return "<html><body>" +
"<h2>JEditorPane 取消异常演示</h2>" +
"<p>按下 Esc 键或快速切换内容可能触发 'Parser method cancelled' 异常。</p>" +
"<p>本演示捕获并处理了该异常。</p>" +
"</body></html>";
}
private String generateComplexHtml() {
StringBuilder sb = new StringBuilder();
sb.append("<html><body>");
for (int i = 0; i < 100; i++) {
sb.append("<div style='border:1px solid #ccc; padding:10px; margin:5px;'>")
.append("<h3>Section ").append(i).append("</h3>")
.append("<p>Content with <b>bold</b>, <i>italic</i>, and ")
.append("<span style='color:red;'>colored text</span></p>")
.append("</div>");
}
sb.append("</body></html>");
return sb.toString();
}
// 安全的编辑器套件
private static class CancellationSafeKit extends HTMLEditorKit {
@Override
public void read(Reader in, Document doc, int pos)
throws IOException, BadLocationException {
try {
super.read(in, doc, pos);
} catch (IOException | BadLocationException e) {
if (isCancellationException(e)) {
// 记录日志但不中断程序
System.err.println("解析取消(安全忽略)");
} else {
throw e;
}
} catch (Exception e) {
if (isCancellationException(e)) {
System.err.println("解析取消(安全忽略)");
} else {
throw new IOException("HTML 解析错误", e);
}
}
}
private boolean isCancellationException(Throwable e) {
String msg = e.getMessage();
return msg != null &&
(msg.contains("cancelled") || msg.contains("Canceled"));
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel());
} catch (Exception e) {
e.printStackTrace();
}
new JEditorPaneCancellationFixDemo().setVisible(true);
});
}
}
| 方案 | 优点 | 缺点 |
|---|---|---|
| 捕获异常 | 实现简单,不影响现有功能 | 异常仍会打印到控制台 |
| 禁用 Esc 键 | 快速解决问题 | 失去了用户期望的取消功能 |
| 重写 EditorKit | 最彻底,可定制性强 | 实现复杂度较高 |
| invokeLater | 符合 Swing 线程模型 | 仅适用于 EDT 问题 |
推荐做法:结合使用 方案 1(捕获异常)+ 方案 2(可选禁用 Esc 键),既能保持功能完整,又能避免程序崩溃。
如果问题仍然存在,请检查是否使用了自定义的 HTMLEditorKit 或 Document 实现,可能需要在自定义代码中添加相应的异常处理。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播