JEditorPane中的pre-wrap

3
我正在使用JEditorPane来显示样式化文本,同时我也在使用<pre>标签来保留文本中的所有空格。问题是我希望JEditorPane能够换行,但HTMLEditorKit(或相关类)不会将文本包装在<pre>标签内。
我的意思是,我想要一种类似于样式表“white-space: pre-wrap”的行为,但似乎HTMLEditorKit不支持它。
您知道一种强制HTMLEditorKit在<pre>标签内包装文本的方法吗,也许是通过扩展它?
我做了一个示例来展示我正在尝试做什么。
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.text.*;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;

public class PreWrapApp extends javax.swing.JFrame {

    public class PreWrapHTMLEditorKit extends HTMLEditorKit {

        ViewFactory viewFactory = new HTMLFactory() {

            @Override
            public View create(Element elem) {
                AttributeSet attrs = elem.getAttributes();
                Object elementName = attrs.getAttribute(AbstractDocument.ElementNameAttribute);
                Object o = (elementName != null) ? null : attrs.getAttribute(StyleConstants.NameAttribute);
                if (o instanceof HTML.Tag) {
                    HTML.Tag kind = (HTML.Tag) o;
                    if (kind == HTML.Tag.PRE) {
                        //View view = new javax.swing.text.html.ParagraphView(elem); // Not wrapping
                        View view = new javax.swing.text.html.ParagraphView(elem.getElement(0)); // Don't show everything
                        return view;
                    }
                }
                return super.create(elem);
            }
        };

        @Override
        public ViewFactory getViewFactory() {
            return this.viewFactory;
        }
    }

    public PreWrapApp() {
        JEditorPane editorPane = new JEditorPane();
        JScrollPane scrollPane = new JScrollPane();

        this.setPreferredSize(new Dimension(300, 300));
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());
        //editorPane.setContentType("text/html");
        editorPane.setEditorKit(new PreWrapHTMLEditorKit());
        editorPane.setText(""
                + "<html>"
                + "<head>"
                + "<style type=\"text/css\">"
                + "pre.c1 { white-space: normal;}" // It is not wrapping
                + "pre.c2 { white-space: pre-wrap;}" // It is not wrapping
                + "p.c3 { white-space: pre;}" // It is not preserving white-spaces
                + "</style>"
                + "</head>"
                + "<body>"
                + "<pre class=\"c1\">long text line long text line long text line long text line (new line here!) \nlong text line long text line long text line long text line</pre>"
                + "<pre class=\"c2\">long text line long text line long text line long text line (new line here!) \nlong text line long text line long text line long text line</pre>"
                + "<p   class=\"c3\">long text line long text line long text line long text line (new line here!) \nlong text line long text line long text line long text line</p>"
                + "</body>"
                + "</html>");
        scrollPane.setViewportView(editorPane);
        getContentPane().add(scrollPane);
        pack();
    }

    public static void main(String args[]) {
        new PreWrapApp().setVisible(true);
    }
}

谢谢。


不确定这能否解决问题,但这个项目看起来非常有趣:http://cssbox.sourceforge.net/swingbox/ - Paolo Fulgoni
2个回答

3

我终于做到了!

你需要做的就是防止创建javax.swing.text.html.LineView。这个视图不会换行。

下面有一个完全可用的示例。

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.text.*;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;

public class PreWrapApp extends javax.swing.JFrame {

    public static class PreWrapHTMLEditorKit extends HTMLEditorKit {

        ViewFactory viewFactory = new HTMLFactory() {

            @Override
            public View create(Element elem) {
                AttributeSet attrs = elem.getAttributes();
                Object elementName = attrs.getAttribute(AbstractDocument.ElementNameAttribute);
                Object o = (elementName != null) ? null : attrs.getAttribute(StyleConstants.NameAttribute);
                if (o instanceof HTML.Tag) {
                    HTML.Tag kind = (HTML.Tag) o;
                    if (kind == HTML.Tag.IMPLIED) {
                        return new javax.swing.text.html.ParagraphView(elem);
                    }
                }
                return super.create(elem);
            }
        };

        @Override
        public ViewFactory getViewFactory() {
            return this.viewFactory;
        }
    }

    public PreWrapApp() {
        JEditorPane editorPane = new JEditorPane();
        JScrollPane scrollPane = new JScrollPane();

        this.setPreferredSize(new Dimension(300, 300));
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());
        editorPane.setEditorKit(new PreWrapHTMLEditorKit());
        editorPane.setText(""
                + "<html>"
                + "<head></head>"
                + "<body>"
                + "<pre>long text line long text line long text line long text line (two new lines here!)\n\n"
                + "long text line long text line long text line long text line long text line long text line</pre>"
                + "</body>"
                + "</html>");
        scrollPane.setViewportView(editorPane);
        getContentPane().add(scrollPane);
        pack();
    }

    public static void main(String args[]) {
        new PreWrapApp().setVisible(true);
    }
}

2

更新2(删除了现在编辑到问题中的错误答案)

您需要寻找一个兼容CSS2+的HTMLEditorKit替代方案。您可以永远等待JWebPane,或者查看一些这些答案。另一种方法是SWT浏览器,如果您有一定的灵活性可以稍微尝试一下。


好的,但是我该如何“包装并返回”呢?我应该返回哪个javax.swing.text.View的子类? - Braulio Horta
你看,当一个人使用<pre>标签时,他想要保留格式,但是拥有pre和wrap并不矛盾。实际上,有一种样式表"white-space: pre-wrap"可以解决这个问题。但是 HTMLEditorKit 不支持它。 :(还有其他的想法吗? - Braulio Horta
抱歉我在CSS方面不太懂。pre-wrap很不错,我会继续寻找一个令人满意的解决方案,如果找到了就会回来发帖。 - Geoffrey Zheng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接