【问题标题】:JTextPane with custom document and editor does not display icons correctly具有自定义文档和编辑器的 JTextPane 无法正确显示图标
【发布时间】:2011-12-11 12:28:16
【问题描述】:

我们正在用 Java 实现一个非常小的消息程序,例如应用程序,并为我们的消息面板使用 JTextPane。现在,我们正在尝试用.gif 文件替换常见的笑脸,并且我们使用了一些可以完成这项工作的示例……除了图标居中对齐而且很烦人。有没有让它看起来内联(左对齐,或正常)?一些帮助解决这个问题将不胜感激。

这是初始化代码:

messagePane = new JTextPane();
messagePane.setEditable(false);
messagePane.setEditorKit(new WrapHTMLEditorKit());
messagePane.setContentType("text/html");
MessageDocument doc = new MessageDocument();
doc.addDocumentListener(new SmileyDocumentListener(messagePane));
messagePane.setStyledDocument(doc);

MessageDocument 类:

public class MessageDocument extends HTMLDocument {

    static private String NEW_LINE = System.getProperty("line.separator");

    static private SimpleAttributeSet DEFAULT_STYLE = new SimpleAttributeSet();
    static private SimpleAttributeSet ANNOUNCE_GLOBAL_STYLE = new SimpleAttributeSet();
    static private SimpleAttributeSet MESSAGE_GLOBAL_STYLE = new SimpleAttributeSet();
    static private SimpleAttributeSet MESSAGE_PRIVATE_STYLE = new SimpleAttributeSet();
    static private SimpleAttributeSet ERROR_STYLE = new SimpleAttributeSet();

    static{
        StyleConstants.setFontFamily(DEFAULT_STYLE, "Courier New");
        StyleConstants.setItalic(DEFAULT_STYLE, true);
        StyleConstants.setForeground(DEFAULT_STYLE, Color.black);       

        StyleConstants.setFontFamily(ANNOUNCE_GLOBAL_STYLE, "Courier New");
        StyleConstants.setBold(ANNOUNCE_GLOBAL_STYLE, true);
        StyleConstants.setForeground(ANNOUNCE_GLOBAL_STYLE, new Color(0, 100, 0));      

        StyleConstants.setFontFamily(MESSAGE_GLOBAL_STYLE, "Courier New");
        StyleConstants.setForeground(MESSAGE_GLOBAL_STYLE, Color.blue);

        StyleConstants.setFontFamily(MESSAGE_PRIVATE_STYLE, "Courier New");
        StyleConstants.setForeground(MESSAGE_PRIVATE_STYLE, Color.black);
        StyleConstants.setBackground(MESSAGE_PRIVATE_STYLE, new Color(220, 220, 255));

        StyleConstants.setFontFamily(ERROR_STYLE, "Courier New");
        StyleConstants.setForeground(ERROR_STYLE, Color.yellow);
        StyleConstants.setBackground(ERROR_STYLE, Color.red);

    }


    public MessageDocument() {
        super();
    }

    public void addMessage(ServerMessage msg) {
        SimpleAttributeSet style;

        if (MessageType.ANNOUNCE_GLOBAL.equals(msg.getType()) || MessageType.CONNECTION_EVENT.equals(msg.getType()) || MessageType.DISCONNECTION_EVENT.equals(msg.getType())) {
            style = ANNOUNCE_GLOBAL_STYLE;
        } else if (MessageType.MESSAGE_GLOBAL.equals(msg.getType())) {
            style = MESSAGE_GLOBAL_STYLE;
        } else if (MessageType.MESSAGE_PRIVATE.equals(msg.getType())) {
            style = MESSAGE_PRIVATE_STYLE;
        } else if (MessageType.ERROR.equals(msg.getType())) {
            style = ERROR_STYLE;
        } else {
            style = DEFAULT_STYLE;
        }

        try {
            insertString(getLength(), msg.getMessage() + NEW_LINE, style);          
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }
}

WrapHTMLEditorKit 类:

public class WrapHTMLEditorKit extends HTMLEditorKit {

    @Override
    public ViewFactory getViewFactory() {

        return new HTMLFactory() {
            public View create(Element e) {
                View v = super.create(e);
                if (v instanceof InlineView) {
                    return new InlineView(e) {
                        public int getBreakWeight(int axis, float pos, float len) {
                            return GoodBreakWeight;
                        }

                        public View breakView(int axis, int p0, float pos, float len) {
                            if (axis == View.X_AXIS) {
                                checkPainter();
                                int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
                                if (p0 == getStartOffset() && p1 == getEndOffset()) {
                                    return this;
                                }
                                return createFragment(p0, p1);
                            }
                            return this;
                        }
                    };
                } else if (v instanceof ParagraphView) {
                    return new ParagraphView(e) {
                        protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
                            if (r == null) {
                                r = new SizeRequirements();
                            }
                            float pref = layoutPool.getPreferredSpan(axis);
                            float min = layoutPool.getMinimumSpan(axis);
                            // Don't include insets, Box.getXXXSpan will include them.
                            r.minimum = (int) min;
                            r.preferred = Math.max(r.minimum, (int) pref);
                            r.maximum = Integer.MAX_VALUE;
                            r.alignment = 0.5f;
                            return r;
                        }

                    };
                }
                return v;
            }
        };
    }
}

最后,SmileyDocumentListener 类:

public class SmileyDocumentListener implements DocumentListener {

    private JTextComponent owner;

    private HashMap<String,ImageIcon> smileMap;

    public SmileyDocumentListener(JTextComponent owner) {
        this.owner = owner;
        this.smileMap = new HashMap<String, ImageIcon>();

        this.smileMap.put(":)", new ImageIcon("resources/images/smileys/smile.gif"));
    }

    @Override
    public void insertUpdate(DocumentEvent event) {
        final DocumentEvent e = event;
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (e.getDocument() instanceof StyledDocument) {
                    try {
                        StyledDocument doc=(StyledDocument)e.getDocument();
                        int start = Utilities.getRowStart(owner, Math.max(0, e.getOffset() - 1));
                        int end = Utilities.getWordStart(owner, e.getOffset() + e.getLength());
                        String text = doc.getText(start, end-start);

                        for (String token : smileMap.keySet()) {
                            int i = text.indexOf(token);
                            while (i >= 0) {
                                final SimpleAttributeSet attrs = new SimpleAttributeSet(doc.getCharacterElement(start + i).getAttributes());
                                if (StyleConstants.getIcon(attrs) == null) {
                                    StyleConstants.setIcon(attrs, smileMap.get(token));
                                    doc.remove(start + i, 2);
                                    doc.insertString(start + i, token, attrs);
                                }
                                i = text.indexOf(token, i+token.length());
                            }
                        }
                    } catch (BadLocationException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        });
    }

    @Override
    public void removeUpdate(DocumentEvent e) {}

    @Override
    public void changedUpdate(DocumentEvent e) {}

}

注意:我已尝试将 WrapHTMLEditorKit.java 中的 r.alignment = 0.5f; 更改为 0.0f

【问题讨论】:

    标签: java swing jtextpane htmleditorkit


    【解决方案1】:

    您可以尝试插入 HTML 标签“”。选择文本并应用一些字符属性(例如粗体)来创建一个单独的叶元素。然后将元素的 HTML 替换为 IMG 标记。

    【讨论】:

    • 我尝试使用StyleConstants.setBold(attrs, true);,但没有成功。您能否举例说明如何使用我提供的类来实现此解决方案?
    【解决方案2】:

    好的,所以我不知道为什么图标在 JTextPane 中使用 text/html 的内容类型以这种方式显示(我尝试使用 JLabel 显示图标、直接设置 HTML 等。 ) 底线是我认为 HTML 是必要的。

    我换了

    public class MessageDocument extends HTMLDocument {
    

    通过

    public class MessageDocument extends StyledDocument {
    

    我删除了WrapHTMLEditorKit并用

    修改了初始化代码
    messagePane = new JTextPane();
    messagePane.setEditable(false);
    messagePane.setEditorKit(new StyledEditorKit());
    MessageDocument doc = new MessageDocument();
    doc.addDocumentListener(new SmileyDocumentListener(messagePane));
    messagePane.setStyledDocument(doc);
    

    图标显示正常。

    内容包装没有特殊的类,我仍然可以使用SimpleAttributeSet 对象。

    【讨论】:

      猜你喜欢
      • 2017-03-19
      • 2016-12-21
      • 1970-01-01
      • 2020-12-13
      • 1970-01-01
      • 2016-10-11
      • 2020-05-20
      • 2011-03-13
      • 1970-01-01
      相关资源
      最近更新 更多