本文目录导读:

这是一个关于 JEditorPane、HTMLEditorKit 以及相关 Actions(操作) 的非常技术性的话题。
在 Java Swing 中,JEditorPane 配合 HTMLEditorKit 提供了一个轻量级的 HTML 渲染和编辑组件。HTMLEditorKit 内置了一套 Action 对象,用于实现富文本编辑功能(如加粗、斜体、插入链接等)。
下面我将详细拆解这些 Actions 的内容、工作原理以及如何使用它们。
核心原理:HTMLEditorKit 的 Action 清单
HTMLEditorKit 类本身注册了大量以 “html-” 为前缀的 Action,你可以通过 HTMLEditorKit.getActions() 获取到这些 Action 数组。
最常用的内置 Action 名称(作为 Action.NAME 或 Action.SHORT_DESCRIPTION 的 key):
| Action 名称 (String) | 用途 | 对应 HTML 标签/效果 |
|---|---|---|
InsertHTML |
插入一段原始的 HTML 代码 | 任意 HTML 片段 |
InsertBreak |
插入 <br> 换行 |
换行而不分段 |
InsertContent |
插入纯文本内容 | 普通文本 |
InsertUnorderedListItem |
将当前行变为无序列表项 (<ul><li>) |
<li> |
InsertOrderedListItem |
将当前行变为有序列表项 (<ol><li>) |
<li> |
InsertTableRow |
在当前表格中插入一行 | <tr> |
InsertTableColumn |
在当前表格中插入一列 | <td> |
InsertTableDataCell |
插入一个数据单元格 | <td> |
InsertTableHeaderCell |
插入一个表头单元格 | <th> |
InsertHorizontalRule |
插入水平分割线 | <hr> |
InsertLink |
插入超链接 | <a href> |
InsertImage |
插入图片 | <img> |
Bold / Italic / Underline |
设置/取消粗体、斜体、下划线 | <b> / <i> / <u> |
StrikeThrough |
设置/取消删除线 | <strike> / <s> |
Superscript / Subscript |
设置/取消上标/下标 | <sup> / <sub> |
FontFamily |
设置字体族 | style="font-family:xxx" |
FontSize |
设置字体大小 | <font size="x"> 或 style |
FontColor |
设置字体颜色 | <font color="..." 或 style |
FontBackgroundColor |
设置背景颜色 | style="background-color:..." |
AlignLeft / AlignCenter / AlignRight |
设置段落对齐方式 | style="text-align:..." |
IndentLeft / IndentRight |
增加/减少段落缩进 | style="margin-left:..." |
获取与执行这些 Actions 的几种方式
方式 A:直接从 HTMLEditorKit 获取 (推荐用于绑定菜单/按钮)
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
public class HTMLEditorActionsExample {
public static void main(String[] args) {
JFrame frame = new JFrame("HTMLEditorKit Actions Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JEditorPane editorPane = new JEditorPane();
editorPane.setContentType("text/html");
editorPane.setText("<html><body><p>Hello <b>World</b></p></body></html>");
// 1. 获取 HTMLEditorKit
HTMLEditorKit kit = (HTMLEditorKit) editorPane.getEditorKit();
// 2. 获取所有 Actions
Action[] actions = kit.getActions();
// 3. 将 Actions 绑定到按钮 (示例:Bold 和 Italic)
JToolBar toolbar = new JToolBar();
for (Action action : actions) {
String name = (String) action.getValue(Action.NAME);
if ("bold".equalsIgnoreCase(name)) {
JButton boldBtn = new JButton(action);
boldBtn.setText("B");
boldBtn.setFont(boldBtn.getFont().deriveFont(java.awt.Font.BOLD));
toolbar.add(boldBtn);
} else if ("italic".equalsIgnoreCase(name)) {
JButton italicBtn = new JButton(action);
italicBtn.setText("I");
italicBtn.setFont(italicBtn.getFont().deriveFont(java.awt.Font.ITALIC));
toolbar.add(italicBtn);
}
}
frame.add(toolbar, java.awt.BorderLayout.NORTH);
frame.add(new JScrollPane(editorPane), java.awt.BorderLayout.CENTER);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
方式 B:通过 ActionMap 和 KeyStroke 绑定快捷键
适用于已有的 Action 名(不限于 HTML 的,也可以是编辑的如 copy, paste)。
// 获取组件的 ActionMap
ActionMap am = editorPane.getActionMap();
// 假设我们要给 "InsertLink" 绑定 Ctrl+L
Action insertLinkAction = am.get("InsertLink");
if (insertLinkAction != null) {
InputMap im = editorPane.getInputMap(JComponent.WHEN_FOCUSED);
KeyStroke ks = KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_L,
java.awt.event.InputEvent.CTRL_DOWN_MASK);
im.put(ks, "InsertLink"); // KeyStroke 映射到 Action 名称
// (注意: 上面的 put 方法会自动用 ActionMap 中的对应 Action)
}
方式 C:直接创建 Action 对象并手动执行
你可以自己创建 StyledEditorKit 或 HTMLEditorKit 的子类,或者直接实例化某个内部 Action(如果允许),但更推荐的方式是 getActions()。
如果你只是想“模拟”用户点击了某个按钮,可以调用 Action 的 actionPerformed 方法:
Action boldAction = am.get("bold");
if (boldAction != null) {
boldAction.actionPerformed(new ActionEvent(editorPane,
ActionEvent.ACTION_PERFORMED,
"bold"));
}
进阶:自定义 Action 或扩展 HTMLEditorKit
有时你需要实现一些内置 Actions 不支持的复杂功能(例如插入自定义的 <div>、修改 CSS 类、插入复杂的表格结构),这时有两个常见路径:
路径 1:继承 HTMLEditorKit 并重写 getActions()
public class MyHTMLKit extends HTMLEditorKit {
@Override
public Action[] getActions() {
// 获取父类的所有 Actions
Action[] parentActions = super.getActions();
// 创建一个新的 Action 数组,增加一个自定义 Action
Action[] myActions = new Action[parentActions.length + 1];
System.arraycopy(parentActions, 0, myActions, 0, parentActions.length);
myActions[parentActions.length] = new MyCustomHTMLAction("MyInsertDiv");
return myActions;
}
class MyCustomHTMLAction extends TextAction {
public MyCustomHTMLAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
JEditorPane editor = getEditor(e);
if (editor != null) {
HTMLDocument doc = (HTMLDocument) editor.getDocument();
try {
// 插入一个自定义 <div class="my-class">
doc.insertAfterStart(doc.getCharacterElement(editor.getCaretPosition()),
"<div class=\"my-class\">New Content</div>");
} catch (BadLocationException | IOException ex) {
ex.printStackTrace();
}
}
}
}
}
然后在 JEditorPane 上使用这个自定义 Kit:
editorPane.setEditorKit(new MyHTMLKit());
路径 2:使用 HTMLEditorKit.InsertHTMLTextAction 的子类
InsertHTMLTextAction 是 HTMLEditorKit 内部用于插入复杂 HTML 结构的抽象类,你可以继承它,实现 insertHTML 方法。
实用技巧与注意事项
-
编辑模式:确保
editorPane.setEditable(true);,默认为true,但布局时可能不小心改掉。 -
光标位置:大多数 Action(如加粗、插入链接)依赖于当前光标位置或选区,如果光标不在可编辑的文本区域(例如在
<html>或<body>标签本身),这些 Action 可能不会生效。 -
Document 类型:这些 Actions 默认操作的是
HTMLDocument,如果你自己替换了 Document 类型(例如换成PlainDocument),这些 Actions 会失效。 -
状态同步:内置的
Bold、Italic等 Action 是有状态的(Toggle 类型),当你在 UI 中点击加粗按钮时,最好实时检查当前光标所在的字符是否有加粗样式,以更新按钮的选中状态,这需要监听光标移动事件并查询HTMLDocument的CharacterAttributes。// 检查当前字符是否粗体 HTMLDocument doc = (HTMLDocument) editorPane.getDocument(); Element elem = doc.getCharacterElement(editorPane.getCaretPosition()); AttributeSet attrs = elem.getAttributes(); // 注意: 需要检查 attrs 中是否包含 HTML.Tag.B 或 CSS 的 font-weight: bold boolean isBold = attrs.containsAttribute(HTML.Attribute.WEIGHT, "bold") || attrs.containsAttribute(StyleConstants.Bold, true); -
性能:高频率使用
insertAfterStart/insertBeforeEnd等操作修改 DOM 会导致性能问题,如果做大量编辑操作,考虑在编辑前锁定 Document(writeLock()),但小心死锁。
| 要点 | 说明 |
|---|---|
| 获取 Actions | new HTMLEditorKit().getActions() 或 editorPane.getActionMap() |
| 常用 Action 名称 | Bold, Italic, Underline, InsertLink, InsertHTML, AlignLeft 等 |
| 绑定方式 | 直接 new JButton(action); 或通过 InputMap + KeyStroke 绑定快捷键 |
| 自定义扩展 | 继承 HTMLEditorKit 并重写 getActions() 或继承 InsertHTMLTextAction |
| 注意事项 | 光标位置影响 Action 目标;Document 必须是 HTMLDocument;Toggle 类 Action 需要手动同步 UI 状态 |
如果你有具体的需求(如何实现一个插入表格的操作”或“如何让加粗按钮实时反映选中文本的样式”),我可以提供更具体的代码实现。