本文目录导读:

我来详细介绍 JEditorPane、HTMLEditorKit 和解析器监控(Parser Monitor)的相关内容。
JEditorPane 与 HTMLEditorKit 概述
JEditorPane
- Swing 中的轻量级 HTML 渲染组件
- 支持 HTML 3.2 和部分 CSS 功能
- 使用
HTMLEditorKit作为默认编辑器
HTMLEditorKit
JEditorPane editorPane = new JEditorPane();
HTMLEditorKit kit = new HTMLEditorKit();
editorPane.setEditorKit(kit);
editorPane.setContentType("text/html");
解析器监控(Parser Monitor)
基本实现
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
import javax.swing.text.*;
public class HTMLParserMonitor {
public static void main(String[] args) {
JEditorPane editorPane = new JEditorPane();
// 创建自定义的 HTMLEditorKit
HTMLEditorKit kit = new HTMLEditorKit() {
@Override
public Document createDefaultDocument() {
HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
// 设置解析器监控
doc.setParser(new DocumentParser() {
@Override
public void parse(Reader r, HTMLDocument doc) throws IOException {
System.out.println("开始解析 HTML...");
super.parse(r, doc);
System.out.println("HTML 解析完成");
}
});
return doc;
}
};
editorPane.setEditorKit(kit);
}
}
完整的监控实现
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;
import java.io.*;
public class ParserMonitorExample {
public static class MonitoredHTMLEditorKit extends HTMLEditorKit {
@Override
public Document createDefaultDocument() {
HTMLDocument doc = new HTMLDocument() {
@Override
public void parse(Reader r) throws IOException {
System.out.println("=== 开始解析 HTML 文档 ===");
long startTime = System.currentTimeMillis();
// 添加解析监听器
addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
System.out.println("插入内容: " + e.getOffset() + ", 长度: " + e.getLength());
}
@Override
public void removeUpdate(DocumentEvent e) {
System.out.println("删除内容: " + e.getOffset() + ", 长度: " + e.getLength());
}
@Override
public void changedUpdate(DocumentEvent e) {
System.out.println("修改内容: " + e.getOffset() + ", 长度: " + e.getLength());
}
});
// 执行解析
try {
super.parse(r);
} catch (Exception e) {
System.err.println("解析错误: " + e.getMessage());
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("=== 解析完成,耗时: " + (endTime - startTime) + "ms ===");
}
};
return doc;
}
@Override
public ViewFactory getViewFactory() {
return new HTMLFactory() {
@Override
public View create(Element elem) {
View view = super.create(elem);
if (view != null) {
System.out.println("创建视图: " + view.getClass().getSimpleName()
+ " 元素: " + elem.getName());
}
return view;
}
};
}
}
// 使用示例
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("HTML Parser Monitor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
JEditorPane editorPane = new JEditorPane();
MonitoredHTMLEditorKit kit = new MonitoredHTMLEditorKit();
editorPane.setEditorKit(kit);
// 设置 HTML 内容
String html = "<html><body><h1>标题</h1><p>段落内容</p></body></html>";
editorPane.setText(html);
JScrollPane scrollPane = new JScrollPane(editorPane);
frame.add(scrollPane);
frame.setVisible(true);
// 监控解析过程
monitorParsing(editorPane);
});
}
private static void monitorParsing(JEditorPane editorPane) {
HTMLDocument doc = (HTMLDocument) editorPane.getDocument();
doc.addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
printDocumentInfo(doc);
}
@Override
public void removeUpdate(DocumentEvent e) {
printDocumentInfo(doc);
}
@Override
public void changedUpdate(DocumentEvent e) {
printDocumentInfo(doc);
}
});
}
private static void printDocumentInfo(HTMLDocument doc) {
System.out.println("\n文档信息:");
System.out.println("元素数量: " + doc.getLength());
System.out.println("段落数量: " + countElements(doc, HTML.Tag.P));
System.out.println("标题数量: " + countElements(doc, HTML.Tag.H1));
System.out.println("-------------------");
// 列出所有元素
Element root = doc.getDefaultRootElement();
printElementTree(root, 0);
}
private static int countElements(HTMLDocument doc, HTML.Tag tag) {
int count = 0;
Element root = doc.getDefaultRootElement();
count = countElementsRecursive(root, tag);
return count;
}
private static int countElementsRecursive(Element element, HTML.Tag tag) {
int count = 0;
AttributeSet attrs = element.getAttributes();
Object name = attrs.getAttribute(StyleConstants.NameAttribute);
if (name == tag) {
count++;
}
for (int i = 0; i < element.getElementCount(); i++) {
count += countElementsRecursive(element.getElement(i), tag);
}
return count;
}
private static void printElementTree(Element element, int indent) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < indent; i++) {
sb.append(" ");
}
AttributeSet attrs = element.getAttributes();
Object name = attrs.getAttribute(StyleConstants.NameAttribute);
sb.append("元素: ").append(name != null ? name.toString() : "unknown");
if (element.isLeaf()) {
sb.append(" [leaf]");
try {
int start = element.getStartOffset();
int end = element.getEndOffset();
Document doc = element.getDocument();
String content = doc.getText(start, end - start);
sb.append(" 内容: '").append(content.trim()).append("'");
} catch (BadLocationException e) {
// ignore
}
}
System.out.println(sb.toString());
for (int i = 0; i < element.getElementCount(); i++) {
printElementTree(element.getElement(i), indent + 1);
}
}
}
高级监控功能
自定义标签处理器
public class CustomTagHandler extends HTMLDocument.HTMLReader.TagAction {
@Override
public void start(HTMLDocument.HTMLReader.TagAction t, HTML.Tag tag, MutableAttributeSet attrs) {
System.out.println("开始标签: " + tag);
if (attrs != null) {
System.out.println(" 属性: " + attrs);
}
super.start(t, tag, attrs);
}
@Override
public void end(HTMLDocument.HTMLReader.TagAction t, HTML.Tag tag) {
System.out.println("结束标签: " + tag);
super.end(t, tag);
}
}
性能监控
public class PerformanceMonitor {
private long startTime;
private int elementCount;
public void startTracking() {
startTime = System.currentTimeMillis();
elementCount = 0;
}
public void trackElement(Element element) {
elementCount++;
}
public void printReport() {
long duration = System.currentTimeMillis() - startTime;
System.out.println("解析性能报告:");
System.out.println(" 元素总数: " + elementCount);
System.out.println(" 解析耗时: " + duration + "ms");
System.out.println(" 平均速度: " + (elementCount / (duration / 1000.0)) + " 元素/秒");
}
}
注意事项
- 线程安全:Swing 组件需要在事件调度线程(EDT)中操作
- 性能影响:监控功能会增加性能开销
- 内存使用:大量文档解析时注意内存管理
- 解析限制:Swing HTML 解析器支持有限,复杂 HTML 可能需要其他库
这个监控系统可以帮助开发人员了解 HTML 文档的解析过程,调试渲染问题,以及优化性能。