0

我正在使用 和 实现一个简单的 HTML 编辑JTextPane器。代码如下所示:HTMLDocumentHTMLEditorKit

public class SimpleHTMLEditor extends JFrame {

    private static final long   serialVersionUID = 1L;

    private final JTextPane   textPane;

    private final HTMLEditorKit edtKit;

    private HTMLDocument  doc;

    public static void main(String[] args) {
        final SimpleHTMLEditor editor = new SimpleHTMLEditor();
        editor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        editor.setVisible(true);
    }

    public SimpleHTMLEditor() {
        super("Simple HTML Editor");
        textPane = new JTextPane();
        edtKit = new HTMLEditorKit();
        textPane.setEditorKit(edtKit);
        doc = new HTMLDocument();
        textPane.setDocument(doc);

    final Container content = getContentPane();
        content.add(textPane, BorderLayout.CENTER);
        content.add(createToolBar(), BorderLayout.NORTH);
        setJMenuBar(createMenuBar());
        setSize(500, 240);
        textPane.requestFocusInWindow();
    }

    /**
     * Creates the toolbar with the combo box that allows for creation and
     * use of different conditions with their respective presentation styles.
     * @return The toolbar
     */
    private JToolBar createToolBar() {
        final JToolBar bar = new JToolBar();
        return bar;
    }

    /**
     * Creates the menu bar. It contains:
     * <li> Actions to read/write HTML file
     * <li> Action to display the HTML source in a popup window.
     * @return The menu bar
     */
    private JMenuBar createMenuBar() {
        final JMenuBar menubar = new JMenuBar();
        final JMenu mnuFile = new JMenu("File");
        menubar.add(mnuFile);
        final SaveAction actSave = new SaveAction();
        mnuFile.add(actSave);
        final LoadAction actLoad = new LoadAction();
        mnuFile.add(actLoad);
        final JMenuItem mnuPreview = new JMenuItem("Preview");
        menubar.add(mnuPreview);
        mnuPreview.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                final HTMLPreview previewer = new HTMLPreview(SimpleHTMLEditor.this,
                                                              getDocSource());
                previewer.setVisible(true);
            }
        });

    return menubar;
    }

    /**
     * Helper method to extract the HTML source code from the HTML document
     * @return The HTML source code
     */
    private String getDocSource() {
        final StringWriter sw = new StringWriter();
        try {
            edtKit.write(sw, doc, 0, doc.getLength());
        } catch (IOException | BadLocationException e1) {
            e1.printStackTrace();
        }
        try {
            sw.close();
        } catch (final IOException e1) {
            e1.printStackTrace();
        }
        return sw.toString();
    }

    class SaveAction extends AbstractAction {
        private static final long serialVersionUID = 1L;
        public SaveAction() {
            super("Save to File");
        }
        @Override
        public void actionPerformed(ActionEvent ev) {
            final JFileChooser chooser = new JFileChooser();
            if (chooser.showSaveDialog(SimpleHTMLEditor.this) != JFileChooser.APPROVE_OPTION)
                return;
            final File targetFile = chooser.getSelectedFile();
            if (targetFile == null)
                return;
            FileWriter writer = null;
            try {
                writer = new FileWriter(targetFile);
                textPane.write(writer);
            } catch (final IOException ex) {
                JOptionPane.showMessageDialog(SimpleHTMLEditor.this,
                                              "File Not Saved", "ERROR",
                                              JOptionPane.ERROR_MESSAGE);
            } finally {
                if (writer != null) {
                    try {
                        writer.close();
                    } catch (final IOException x) {
                    }
                }
            }
        }
    }

    class LoadAction extends AbstractAction {
        private static final long serialVersionUID = 1L;
        public LoadAction() {
            super("Load from File");
        }
        @Override
        public void actionPerformed(ActionEvent ev) {
            final JFileChooser chooser = new JFileChooser();
            if (chooser.showOpenDialog(SimpleHTMLEditor.this) != JFileChooser.APPROVE_OPTION)
                return;
            final File sourceFile = chooser.getSelectedFile();
            if (sourceFile == null)
                return;
            FileReader reader = null;
            try {
                reader = new FileReader(sourceFile);
                doc = (HTMLDocument)edtKit.createDefaultDocument();
                textPane.setDocument(doc);
                edtKit.read(reader,doc,0);
            } catch (final IOException ex) {
                JOptionPane.showMessageDialog(SimpleHTMLEditor.this,
                                              "File '" + sourceFile.getAbsolutePath() +
                                              "' Not Loaded", "ERROR",
                                              JOptionPane.ERROR_MESSAGE);

        } catch (final BadLocationException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (final IOException x) {
                    }
                }
            }
        }
    }
}

/**
 * Popup window for display of the current contents of the editor as HTML
 * source code.
 */
class HTMLPreview extends JDialog {

    private static final long serialVersionUID = 1L;

    public HTMLPreview(JFrame parent, String source) {
        super(parent, "HTML Source", true);

        final JPanel pp = new JPanel(new BorderLayout());
        pp.setBorder(new EmptyBorder(10, 10, 5, 10));

        final JTextArea srcTxtArea = new JTextArea(source, 20, 60);
        srcTxtArea.setFont(new Font("Courier", Font.PLAIN, 12));
        final JScrollPane sp = new JScrollPane(srcTxtArea);
        pp.add(sp, BorderLayout.CENTER);

        final JPanel p = new JPanel(new FlowLayout());
        final JPanel p1 = new JPanel(new GridLayout(1, 2, 10, 0));

        final JButton closeBtn = new JButton("Close");
        closeBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
        p1.add(closeBtn);
        p.add(p1);
        pp.add(p, BorderLayout.SOUTH);
        getContentPane().add(pp, BorderLayout.CENTER);
        pack();
        setResizable(true);
        setLocationRelativeTo(parent);
    }
}

我注意到,当我加载一个包含嵌套 SPAN 元素的 HTML 文件时,嵌套会被静默删除。这是一个示例 HTML 文件:

<html>
  <head>
  </head>
  <body>
    <p>
      <span title="tag:one">Outer span. <span title="tag:two">Inner span.</span> Outer span continued.</span>
    </p>
  </body>
</html>

加载该文件并在工具栏中选择“预览”操作后,我会看到一个显示 HTML 源代码的弹出窗口,如下所示:

<html>
  <head>
  </head>
  <body>
    <p>
      <span title="tag:one">Outer span.</span> <span title="tag:two">Inner 
  span.</span> <span title="tag:one"> Outer span continued.</span>
    </p>
  </body>
</html>

可以看出,外部 SPAN 元素被无声地分成两个 SPAN 元素,内部 SPAN 元素放置在两者之间。在我看来,这种行为显示了实现 HTML 编辑器的 Java Swing 组件与据我所知允许嵌套 SPAN 元素的 HTML 4.x 标准之间的不兼容之一。我现在的问题是:是否有一种(希望不会太复杂)方法来解决或克服该限制,即让 HTML 编辑器保留它在阅读 HTML 文本时遇到的嵌套 SPAN 元素?

非常感谢提前,apatwork。

4

1 回答 1

1

对于查看,请考虑通过Desktop#browse(). 对于编辑,SO 撰稿人@stanislavl已就该主题撰写了几篇相关文章,并在此处进行了广泛回答。特别是,JEditorPane/JTextPane 中的 HTMLEditorKit 和自定义标签可能会提供一些关于可行性的见解。

于 2013-09-24T09:38:17.877 回答