不可编辑的 JEditorPane 使用 Enter 键

Non-editable JEditorPane consumes Enter key

我有一个 JDialog 包含一个 JEditorPane 用于显示非用户可编辑的 HTML 内容,例如帮助和发行说明。

JDialog 有一个作为默认按钮安装的 "Close" 按钮。

如果 JEditorPane 离开 "focusable",则页面 Up/Down 键将滚动浏览文档,但按 "Enter" 不会触发默认按钮。

另一方面,如果 JEditorPane 设置为不可聚焦,则 Page Up/Down 键不起作用,但按 "Enter" 键会触发默认按钮,关闭对话框。

@SuppressWarnings("serial")
public class NoteViewer extends JFrame {

  public static void main(String[] args) throws IOException {
    final NoteViewer viewer = new NoteViewer(new URL("http://example.com/"));
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            viewer.setVisible(true);
        }
    });
  }

  public NoteViewer(URL url) throws IOException {
    super("Note Viewer");
    setSize(900, 200);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JEditorPane notes = new JEditorPane(url);
    notes.setEditable(false);
    // notes.setFocusable(false);

    getContentPane().add(new JScrollPane(notes), BorderLayout.CENTER);

    JButton close = new JButton("Close");
    close.addActionListener(EventHandler.create(ActionListener.class, this, "dispose"));
    Box box = Box.createHorizontalBox();
    box.add(Box.createHorizontalGlue());
    box.add(close);
    getContentPane().add(box, BorderLayout.PAGE_END);

    getRootPane().setDefaultButton(close);
  }
}

取消注释 notes.setFocusable(false) 行以查看不同的行为。

我希望 JEditorPane 处理导航击键(例如 Page Up/Down),但忽略(不消耗)"editing" 击键,例如 Enter,这样根窗格将调用默认按钮。

经过大量的黑客攻击和单步执行后,我得到了我正在使用这段代码寻找的行为:

notes.getInputMap().put(
    KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
    "pressed");

但我担心它相当脆弱。所有平台都使用 VK_ENTER 来调用默认按钮吗?是否所有平台都使用 "pressed" 作为调用默认按钮的命令字符串?

最后,它以错误的方式进行处理:而不是 JEditorPane 忽略回车键并让处理发生在祖先中,这是 JEditorPane 明确处理回车键,我认为这是错误的。

不可编辑的 JEditorPane 不应捕获所有编辑击键(A-Z、0-9、Enter、Delete 等)并将它们转换为警告蜂鸣声,而应不处理它们,以便父组件有机会。这如何以通用的、非逐键输入映射方式实现?

Do all platforms use "pressed" as the command-string to invoke the default button?

事实并非如此。

您正在将 Enter 键映射到 JEditorPane 的 "pressed" 操作。但是,没有 "pressed" 操作,因此绑定被忽略,事件向上传递到使用默认按钮的 Enter 键绑定的根窗格。

通常"none"用来表示要ignore/remove绑定。查看 How to Remove Bindings 上的 Swing 教程部分了解更多信息。

所以我会说你的解决方案是正确的,应该适用于所有平台。

您可能想要查看 Key Bindings 的程序,该程序显示每个组件的所有键绑定。您会看到没有 "pressed" 操作。 JEdi​​torPane 实际上使用 "insert-break" 映射到 Action.

A non-editable JEditorPane should not capture all the editing keystrokes (A-Z, 0-9, Enter, Delete, etc.) and transform them into a warning beep,

我对 a-z、0-9 没有 "beeping" 问题。我的删除键和退格键确实有问题。

我在 Windows 7.

上使用 JDK8_45

也许您可以使用 KeyEventDispatcher 来阻止密钥的发送。也许您检查了 KeyEvent 的来源,如果来源是编辑器窗格,您只让 Enter 键通过?可能还需要允许 PageUp/PageDown 事件,这样滚动才会起作用。

查看 Global Event Dispatching 了解更多信息。

我想我找到了一个更好的方法:将 JEditorPane 设置为不可编辑且不可聚焦,将 JScrollPane 设置为可聚焦。

JEditorPane notes = new JEditorPane(url);
notes.setEditable(false);
notes.setFocusable(false);

JScrollPane scroller = new JScrollPane(notes);
scroller.setFocusable(true);
getContentPane().add(scroller, BorderLayout.CENTER);

Enter 键转发到默认按钮。退格键、删除键和好友不会发出任何蜂鸣声。

编辑: 不允许选择和复制任何文本,因此可能不是最佳解决方案。