本文目录导读:

我来详细解释 JEditorPane、HTMLEditorKit、Parser 和 Handler 这几个核心组件及其关系。
这是 Java Swing 中用于显示和编辑 HTML 内容的组件体系,它们共同构成了一个完整的内容处理管道。
核心组件关系
graph TB
A[JEditorPane] --> B[HTMLEditorKit]
B --> C[ViewFactory]
B --> D[Parser]
D --> E[ParserCallback/Handler]
E --> F[Document]
F --> G[Views]
详细说明
JEditorPane
// 基础用法
JEditorPane editorPane = new JEditorPane();
editorPane.setContentType("text/html"); // 设置内容类型
editorPane.setText("<html><body><h1>Hello World</h1></body></html>");
// 设置编辑器
editorPane.setEditorKit(new HTMLEditorKit());
HTMLEditorKit
public class CustomHTMLEditorKit extends HTMLEditorKit {
@Override
public Document createDefaultDocument() {
HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
// 自定义文档设置
return doc;
}
@Override
public ViewFactory getViewFactory() {
return new HTMLFactory() {
@Override
public View create(Element elem) {
// 自定义视图创建
return super.create(elem);
}
};
}
}
Parser 和 Handler
基础 Parser 使用
public class CustomHTMLParser {
public static void main(String[] args) throws Exception {
String html = "<html><body><p>Hello <b>World</b></p></body></html>";
// 创建解析器
ParserDelegator parser = new ParserDelegator();
// 创建回调处理器
HTMLEditorKit.ParserCallback callback = new HTMLEditorKit.ParserCallback() {
@Override
public void handleText(char[] data, int pos) {
System.out.println("Text: " + new String(data) + " at position " + pos);
}
@Override
public void handleStartTag(HTML.Tag t,
MutableAttributeSet a,
int pos) {
System.out.println("Start tag: " + t + " at " + pos);
}
@Override
public void handleEndTag(HTML.Tag t, int pos) {
System.out.println("End tag: " + t + " at " + pos);
}
@Override
public void handleSimpleTag(HTML.Tag t,
MutableAttributeSet a,
int pos) {
System.out.println("Simple tag: " + t + " at " + pos);
}
@Override
public void handleComment(char[] data, int pos) {
System.out.println("Comment: " + new String(data));
}
@Override
public void handleEndOfLineString(String eol) {
// 处理行结束
}
};
// 执行解析
Reader reader = new StringReader(html);
parser.parse(reader, callback, true);
}
}
自定义 Document 解析器
public class CustomDocumentParser {
public static class CustomParserCallback extends HTMLEditorKit.ParserCallback {
private StringBuilder sb = new StringBuilder();
private int depth = 0;
@Override
public void handleStartTag(HTML.Tag t,
MutableAttributeSet a,
int pos) {
// 缩进显示
String indent = " ".repeat(depth);
sb.append(indent).append("<").append(t);
// 处理属性
Enumeration<?> names = a.getAttributeNames();
while (names.hasMoreElements()) {
Object name = names.nextElement();
sb.append(" ").append(name).append("='")
.append(a.getAttribute(name)).append("'");
}
sb.append(">\n");
depth++;
}
@Override
public void handleEndTag(HTML.Tag t, int pos) {
depth--;
String indent = " ".repeat(depth);
sb.append(indent).append("</").append(t).append(">\n");
}
@Override
public void handleText(char[] data, int pos) {
String indent = " ".repeat(depth);
sb.append(indent).append(new String(data)).append("\n");
}
public String getResult() {
return sb.toString();
}
}
public static void main(String[] args) throws Exception {
String html = "<html><body><div class='content'><p>Hello <b>World</b></p></div></body></html>";
ParserDelegator parser = new ParserDelegator();
CustomParserCallback callback = new CustomParserCallback();
parser.parse(new StringReader(html), callback, true);
System.out.println("Parsed HTML structure:");
System.out.println(callback.getResult());
}
}
完整的 HTML 编辑器示例
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import java.awt.*;
public class CompleteHTMLEditorExample {
private JFrame frame;
private JEditorPane editorPane;
private HTMLDocument document;
public void createAndShowGUI() {
frame = new JFrame("HTML Editor Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
// 创建编辑器
editorPane = new JEditorPane();
editorPane.setContentType("text/html");
editorPane.setEditable(true);
// 设置自定义编辑器
HTMLEditorKit kit = new HTMLEditorKit();
editorPane.setEditorKit(kit);
// 创建文档
document = (HTMLDocument) kit.createDefaultDocument();
editorPane.setDocument(document);
// 设置初始内容
String initialContent = "<html><body>" +
"<h1>HTML Editor</h1>" +
"<p>This is a <b>demo</b> of HTML editing.</p>" +
"<ul><li>Item 1</li><li>Item 2</li></ul>" +
"</body></html>";
editorPane.setText(initialContent);
// 添加滚动面板
JScrollPane scrollPane = new JScrollPane(editorPane);
frame.add(scrollPane, BorderLayout.CENTER);
// 添加工具栏
JToolBar toolbar = createToolBar();
frame.add(toolbar, BorderLayout.NORTH);
// 添加解析信息显示
JTextArea parseInfo = new JTextArea(10, 40);
parseInfo.setEditable(false);
frame.add(new JScrollPane(parseInfo), BorderLayout.SOUTH);
// 解析并显示结构
parseAndDisplayStructure();
frame.setVisible(true);
}
private JToolBar createToolBar() {
JToolBar toolbar = new JToolBar();
JButton boldBtn = new JButton("Bold");
boldBtn.addActionListener(e -> toggleBold());
toolbar.add(boldBtn);
JButton italicBtn = new JButton("Italic");
italicBtn.addActionListener(e -> toggleItalic());
toolbar.add(italicBtn);
JButton underlineBtn = new JButton("Underline");
underlineBtn.addActionListener(e -> toggleUnderline());
toolbar.add(underlineBtn);
toolbar.addSeparator();
JButton parseBtn = new JButton("Parse Structure");
parseBtn.addActionListener(e -> parseAndDisplayStructure());
toolbar.add(parseBtn);
return toolbar;
}
private void toggleBold() {
// 实现粗体切换
Action action = new StyledEditorKit.BoldAction();
action.actionPerformed(new java.awt.event.ActionEvent(
editorPane,
java.awt.event.ActionEvent.ACTION_PERFORMED,
""
));
}
private void toggleItalic() {
Action action = new StyledEditorKit.ItalicAction();
action.actionPerformed(new java.awt.event.ActionEvent(
editorPane,
java.awt.event.ActionEvent.ACTION_PERFORMED,
""
));
}
private void toggleUnderline() {
Action action = new StyledEditorKit.UnderlineAction();
action.actionPerformed(new java.awt.event.ActionEvent(
editorPane,
java.awt.event.ActionEvent.ACTION_PERFORMED,
""
));
}
private void parseAndDisplayStructure() {
try {
String html = editorPane.getText();
ParserDelegator parser = new ParserDelegator();
StringBuilder structure = new StringBuilder();
structure.append("HTML Structure:\n");
structure.append("===============\n");
parser.parse(new StringReader(html),
new HTMLEditorKit.ParserCallback() {
private int depth = 0;
@Override
public void handleStartTag(HTML.Tag t,
MutableAttributeSet a,
int pos) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) sb.append(" ");
sb.append("<").append(t);
Enumeration<?> names = a.getAttributeNames();
while (names.hasMoreElements()) {
Object name = names.nextElement();
sb.append(" ").append(name).append("='")
.append(a.getAttribute(name)).append("'");
}
sb.append(">\n");
structure.append(sb.toString());
depth++;
}
@Override
public void handleEndTag(HTML.Tag t, int pos) {
depth--;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) sb.append(" ");
sb.append("</").append(t).append(">\n");
structure.append(sb.toString());
}
@Override
public void handleText(char[] data, int pos) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) sb.append(" ");
sb.append(new String(data)).append("\n");
structure.append(sb.toString());
}
}, true);
// 获取底部的文本区域并更新
JScrollPane bottomPane = (JScrollPane) frame.getContentPane()
.getComponent(2);
JTextArea infoArea = (JTextArea) bottomPane.getViewport().getView();
infoArea.setText(structure.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new CompleteHTMLEditorExample().createAndShowGUI();
});
}
}
自定义 Parser Handler 高级示例
public class AdvancedHTMLParserHandler {
// 自定义 Tag 处理器接口
public interface TagHandler {
void handle(HTML.Tag tag, MutableAttributeSet attrs);
}
// 可配置的解析器回调
public static class ConfigurableParserCallback
extends HTMLEditorKit.ParserCallback {
private Map<HTML.Tag, TagHandler> tagHandlers = new HashMap<>();
private Map<HTML.Tag, TagHandler> endTagHandlers = new HashMap<>();
private Consumer<String> textHandler;
private StringBuffer buffer = new StringBuffer();
public void registerTagHandler(HTML.Tag tag, TagHandler handler) {
tagHandlers.put(tag, handler);
}
public void registerEndTagHandler(HTML.Tag tag, TagHandler handler) {
endTagHandlers.put(tag, handler);
}
public void setTextHandler(Consumer<String> handler) {
this.textHandler = handler;
}
@Override
public void handleStartTag(HTML.Tag t,
MutableAttributeSet a,
int pos) {
TagHandler handler = tagHandlers.get(t);
if (handler != null) {
handler.handle(t, a);
}
}
@Override
public void handleEndTag(HTML.Tag t, int pos) {
TagHandler handler = endTagHandlers.get(t);
if (handler != null) {
handler.handle(t, null);
}
}
@Override
public void handleText(char[] data, int pos) {
if (textHandler != null) {
textHandler.accept(new String(data));
}
}
}
// 使用示例
public static void main(String[] args) throws Exception {
String html = "<html><body>" +
"<h1>Title</h1>" +
"<p class='content'>Paragraph text</p>" +
"<a href='http://example.com'>Link</a>" +
"</body></html>";
ConfigurableParserCallback callback = new ConfigurableParserCallback();
// 注册处理器
callback.registerTagHandler(HTML.Tag.A, (tag, attrs) -> {
String href = (String) attrs.getAttribute(HTML.Attribute.HREF);
System.out.println("Link found: " + href);
});
callback.registerTagHandler(HTML.Tag.H1, (tag, attrs) -> {
System.out.println("Heading 1 found");
});
callback.registerTagHandler(HTML.Tag.P, (tag, attrs) -> {
String cls = (String) attrs.getAttribute(HTML.Attribute.CLASS);
System.out.println("Paragraph with class: " + cls);
});
callback.setTextHandler(text -> {
System.out.println("Text content: " + text.trim());
});
// 执行解析
ParserDelegator parser = new ParserDelegator();
parser.parse(new StringReader(html), callback, false);
}
}
- JEditorPane: 显示和编辑 HTML 的组件
- HTMLEditorKit: 提供 HTML 编辑功能的编辑器套件
- Parser: 解析 HTML 内容的解析器
- Handler/Callback: 处理解析过程中的各种事件
这些组件共同提供了完整的 HTML 处理能力,可以用于:
- HTML 内容展示
- 富文本编辑
- HTML 结构分析
- 自定义 HTML 渲染