JEditorPaneHTMLEditorKitActions操作

wen java案例 3

本文目录导读:

JEditorPaneHTMLEditorKitActions操作

  1. 核心原理:HTMLEditorKit 的 Action 清单
  2. 获取与执行这些 Actions 的几种方式
  3. 进阶:自定义 Action 或扩展 HTMLEditorKit
  4. 实用技巧与注意事项

这是一个关于 JEditorPaneHTMLEditorKit 以及相关 Actions(操作) 的非常技术性的话题。

在 Java Swing 中,JEditorPane 配合 HTMLEditorKit 提供了一个轻量级的 HTML 渲染和编辑组件。HTMLEditorKit 内置了一套 Action 对象,用于实现富文本编辑功能(如加粗、斜体、插入链接等)。

下面我将详细拆解这些 Actions 的内容、工作原理以及如何使用它们。

核心原理:HTMLEditorKit 的 Action 清单

HTMLEditorKit 类本身注册了大量以 “html-” 为前缀的 Action,你可以通过 HTMLEditorKit.getActions() 获取到这些 Action 数组。

最常用的内置 Action 名称(作为 Action.NAMEAction.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:通过 ActionMapKeyStroke 绑定快捷键

适用于已有的 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 对象并手动执行

你可以自己创建 StyledEditorKitHTMLEditorKit 的子类,或者直接实例化某个内部 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 的子类

InsertHTMLTextActionHTMLEditorKit 内部用于插入复杂 HTML 结构的抽象类,你可以继承它,实现 insertHTML 方法。

实用技巧与注意事项

  1. 编辑模式:确保 editorPane.setEditable(true);,默认为 true,但布局时可能不小心改掉。

  2. 光标位置:大多数 Action(如加粗、插入链接)依赖于当前光标位置选区,如果光标不在可编辑的文本区域(例如在 <html><body> 标签本身),这些 Action 可能不会生效。

  3. Document 类型:这些 Actions 默认操作的是 HTMLDocument,如果你自己替换了 Document 类型(例如换成 PlainDocument),这些 Actions 会失效。

  4. 状态同步:内置的 BoldItalic 等 Action 是有状态的(Toggle 类型),当你在 UI 中点击加粗按钮时,最好实时检查当前光标所在的字符是否有加粗样式,以更新按钮的选中状态,这需要监听光标移动事件并查询 HTMLDocumentCharacterAttributes

    // 检查当前字符是否粗体
    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);
  5. 性能:高频率使用 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 状态

如果你有具体的需求(如何实现一个插入表格的操作”或“如何让加粗按钮实时反映选中文本的样式”),我可以提供更具体的代码实现。

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