JEditorPane正在移除CSS字体样式。

4

我正在尝试让JEditorPane保留任何CSS字体样式。不幸的是,它似乎会完全剥离段落标签(以及其他标签)中的样式,并将其转换为A标签的字体标签。

考虑以下示例:

import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class EditorPaneTest
{
    public static void main(String[] args)
    {
        String text = "<html><head></head><body><p style=\"padding-right: 10px; padding-left: 10px; font-size: 14px; line-height: 125%; font-family: Verdana;\">This is a test.</p>"
                + "<p><a href=\"http://www.google.com/\" style=\"font-size: 9px; margin-right: 10px; font-style: normal; font-family: Verdana;\">Google</a></p></body></html>";
        JEditorPane editorPane = new JEditorPane("text/html", text);
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(new JScrollPane(editorPane), BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
        text = editorPane.getText();
        System.out.println(text);
    }
}

这将为p和a标签产生以下输出:
<p style="padding-left: 10px; padding-right: 10px; line-height: 125%">

并且

<a href="http://www.google.com/" style="margin-right: 10px"><font size="9px" face="Verdana">Google</font></a>

正如您所看到的,它保留了段落标签的填充和边距样式,但剥离了字体样式,并将其转换为链接标签的字体标签。

在调用getText之前,如果您显示它,它实际上会正确地应用段落样式。

我该如何使它保留原样的字体属性?


1
它为BODY元素定义了哪些样式?为什么要同时使用'verdana'和'Verdana'字符串来设置字体?请注意:1)<a name=..是锚点,而<a href..只是一个链接。2)JEP在使用百分比指定大小时存在固有问题。3)很少有开发人员认为JEP适用于除了精心控制和非常有限的HTML/CSS之外的任何内容。看起来你正在试图将其推向设计极限以外的领域。 - Andrew Thompson
以上的HTML仅是一个示例,以演示问题。我的基本问题仍然存在。它会删除p标签的字体样式,并将其转换为a标签的字体标签。 - Avrom
我知道JEditorPane有其限制,但它显然能够处理CSS字体样式,因为它将使用指定的字体显示它。我只需要让它保持原样就可以了。 - Avrom
我已经成功地在Java组件中完成了CSS样式。请注意,Swing组件甚至可以成功地与外部样式表规范一起使用!但现在我的问题是:您如何知道样式被剥离了,即您如何知道组件内部的内容?您只是在执行setText()之前和之后执行getText()时查看返回的内容吗?在执行getText()后,可见的即显示的样式是否会发生变化? - Carl Smotricz
@Andrew,我已经更新了代码。@Carl,在调用getText后屏幕上的样式没有明显变化,但在我正在调试的应用程序中,它会获取返回的文本并保存它(从而更改它)。因此,你可以说我应该在调用getText之前使用原始的HTML文本,但我不能这样做,因为用户也可能编辑文本。 - Avrom
显示剩余7条评论
1个回答

2

好的,

我发现问题肯定在HTMLWriter类中。不幸的是,他们没有让覆盖这个类变得容易,但我相信我已经解决了。

    import java.io.IOException;
    import java.io.Writer;
    import java.util.Enumeration;
    import java.util.Vector;
    import javax.swing.text.AttributeSet;
    import javax.swing.text.MutableAttributeSet;
    import javax.swing.text.SimpleAttributeSet;
    import javax.swing.text.StyleConstants;
    import javax.swing.text.html.CSS;
    import javax.swing.text.html.HTML;
    import javax.swing.text.html.HTMLDocument;
    import javax.swing.text.html.HTMLWriter;

    public class FixedHTMLWriter extends HTMLWriter
    {
        private Vector                      tags                = new Vector(10);
        private Vector                      tagValues       = new Vector(10);
        private Vector                      tagsToRemove    = new Vector(10);
        private MutableAttributeSet convAttr            = new SimpleAttributeSet();
        private MutableAttributeSet oConvAttr       = new SimpleAttributeSet();

        public FixedHTMLWriter(Writer w, HTMLDocument doc, int pos, int len)
        {
            super(w, doc, pos, len);
        }

        AttributeSet convertToHTML(AttributeSet from, MutableAttributeSet to)
        {
            if (to == null)
            {
                to = convAttr;
            }
            to.removeAttributes(to);
            if (from != null)
            {
                Enumeration keys = from.getAttributeNames();
                String value = "";
                while (keys.hasMoreElements())
                {
                           Object key = keys.nextElement();
                    if (key instanceof CSS.Attribute)
                    {
                        value +=  key + ": " + from.getAttribute(key) + ";";
                        if (keys.hasMoreElements())
                            value += " ";
                    }

                    else
                    {
                        to.addAttribute(key, from.getAttribute(key));
                    }
                }
                if (value.length() > 0)
                {
                    to.addAttribute(HTML.Attribute.STYLE, value);
                }
            }
            return to;
        }

        @Override
        protected void closeOutUnwantedEmbeddedTags(AttributeSet attr) throws IOException
        {
            tagsToRemove.removeAllElements();
            // translate css attributes to html
            attr = convertToHTML(attr, null);
            HTML.Tag t;
            Object tValue;
            int firstIndex = -1;
            int size = tags.size();
            // First, find all the tags that need to be removed.
            for (int i = size - 1; i >= 0; i--)
            {
                t = (HTML.Tag) tags.elementAt(i);
                tValue = tagValues.elementAt(i);
                if ((attr == null) || noMatchForTagInAttributes(attr, t, tValue))
                {
                    firstIndex = i;
                    tagsToRemove.addElement(t);
                }
            }
            if (firstIndex != -1)
            {
                // Then close them out.
                boolean removeAll = ((size - firstIndex) == tagsToRemove.size());
                for (int i = size - 1; i >= firstIndex; i--)
                {
                    t = (HTML.Tag) tags.elementAt(i);
                    if (removeAll || tagsToRemove.contains(t))
                    {
                        tags.removeElementAt(i);
                        tagValues.removeElementAt(i);
                    }
                    write('<');
                    write('/');
                    write(t.toString());
                    write('>');
                }
                // Have to output any tags after firstIndex that still remaing,
                // as we closed them out, but they should remain open.
                size = tags.size();
                for (int i = firstIndex; i < size; i++)
                {
                    t = (HTML.Tag) tags.elementAt(i);
                    write('<');
                    write(t.toString());
                    Object o = tagValues.elementAt(i);
                    if (o != null && o instanceof AttributeSet)
                    {
                        writeAttributes((AttributeSet) o);
                    }
                    write('>');
                }
            }
        }

        private boolean noMatchForTagInAttributes(AttributeSet attr, HTML.Tag t, Object tagValue)
        {
            if (attr != null && attr.isDefined(t))
            {
                Object newValue = attr.getAttribute(t);
                if ((tagValue == null) ? (newValue == null) : (newValue != null && tagValue.equals(newValue)))
                {
                    return false;
                }
            }
            return true;
        }

        @Override
        protected void writeEmbeddedTags(AttributeSet attr) throws IOException
        {
            // translate css attributes to html
            attr = convertToHTML(attr, oConvAttr);
            Enumeration names = attr.getAttributeNames();
            while (names.hasMoreElements())
            {
                Object name = names.nextElement();
                if (name instanceof HTML.Tag)
                {
                    HTML.Tag tag = (HTML.Tag) name;
                    if (tag == HTML.Tag.FORM || tags.contains(tag))
                    {
                        continue;
                    }
                    write('<');
                    write(tag.toString());
                    Object o = attr.getAttribute(tag);
                    if (o != null && o instanceof AttributeSet)
                    {
                        writeAttributes((AttributeSet) o);
                    }
                    write('>');
                    tags.addElement(tag);
                    tagValues.addElement(o);
                }
            }
        }

        @Override
        protected void writeAttributes(AttributeSet attr) throws IOException
        {
            convAttr.removeAttributes(convAttr);
            convertToHTML(attr, convAttr);
            Enumeration names = convAttr.getAttributeNames();
            while (names.hasMoreElements())
            {
                Object name = names.nextElement();
                if (name instanceof HTML.Tag || name instanceof StyleConstants || name == HTML.Attribute.ENDTAG)
                {
                    continue;
                }
                write(" " + name + "=\"" + convAttr.getAttribute(name) + "\"");
            }
        }
    }

您需要覆盖HTMLEditorKit类的方法write,如下所示:

    public void write(Writer out, Document doc, int pos, int len) throws IOException, BadLocationException
        {
            if (doc instanceof HTMLDocument)
            {
                FixedHTMLWriter w = new FixedHTMLWriter(out, (HTMLDocument) doc, pos, len);
                w.write();
            }
            else if (doc instanceof StyledDocument)
            {
                MinimalHTMLWriter w = new MinimalHTMLWriter(out, (StyledDocument) doc, pos, len);
                w.write();
            }
            else
            {
                super.write(out, doc, pos, len);
            }
        }

通过调用setEditorKit,将被覆盖的HTMLEditorKit设置在JEditorPane上。


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