JTextPane/JEditorPane и странная проблема с текстом

Я создаю простую программу чата, в которой я хочу показать ссылки HTML. Моя проблема сейчас в том, что я не могу заставить текст отображаться рядом с именем пользователя так, как я хочу.

Я хочу, чтобы имя пользователя было выделено жирным шрифтом, а рядом с ним должен был отображаться текст, но по какой-то причине не выделенный жирным шрифтом текст отображается по центру.

Если я не выделю имя пользователя, оно будет работать нормально. Верхние две - это то, как это выглядит, когда у меня имена выделены жирным шрифтом, средняя - когда имя не выделено жирным шрифтом, нижняя часть показывает гиперссылку. Я хочу, чтобы она выглядела как две средние, но с выделенными жирным шрифтом именами.

Вот код, что я делаю не так? Обратите внимание, что я попытался заменить JTextPane на JEditorPane, и произошло то же самое.

package com.test;

import java.awt.BorderLayout;
import java.awt.Color;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.WindowConstants;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML;

public class JTextPaneTest extends JPanel {

    JTextPane pane;

    public JTextPaneTest() {
        this.setLayout(new BorderLayout());

        pane = new JTextPane();
        pane.setEditable(false);
        pane.setContentType("text/html");

        JScrollPane scrollPane = new JScrollPane(pane);
        this.add(scrollPane, BorderLayout.CENTER);

        pane.addHyperlinkListener(new HyperlinkListener() {

            @Override
            public void hyperlinkUpdate(HyperlinkEvent e) {
                if (e.getEventType() == EventType.ACTIVATED) {
                    System.out.println(e.getDescription());
                }

            }
        });

    }

    public void chatWithBold(String user, String text) {

        SimpleAttributeSet bold = new SimpleAttributeSet();
        StyleConstants.setBold(bold, true);

        SimpleAttributeSet normal = new SimpleAttributeSet();

        try {
            pane.getDocument().insertString(pane.getDocument().getLength(),
                    user + ": ", bold);
        } catch (BadLocationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            pane.getDocument().insertString(pane.getDocument().getLength(),
                    text + "\n", normal);
        } catch (BadLocationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void chatNoBold(String user, String text) {

        SimpleAttributeSet bold = new SimpleAttributeSet();
        StyleConstants.setBold(bold, true);

        SimpleAttributeSet normal = new SimpleAttributeSet();

        try {
            pane.getDocument().insertString(pane.getDocument().getLength(),
                    user + ": ", normal);
        } catch (BadLocationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            pane.getDocument().insertString(pane.getDocument().getLength(),
                    text + "\n", normal);
        } catch (BadLocationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void submitALinkWithBold(String user, String link) {
        SimpleAttributeSet bold = new SimpleAttributeSet();
        StyleConstants.setBold(bold, true);

        try {
            pane.getDocument().insertString(pane.getDocument().getLength(),
                    user + ": ", bold);
        } catch (BadLocationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        SimpleAttributeSet attrs = new SimpleAttributeSet();
        attrs.addAttribute(HTML.Attribute.HREF, link);

        SimpleAttributeSet htmlLink = new SimpleAttributeSet();
        htmlLink.addAttribute(HTML.Tag.A, attrs);
        StyleConstants.setUnderline(htmlLink, true);
        StyleConstants.setForeground(htmlLink, Color.BLUE);
        try {
            pane.getDocument().insertString(pane.getDocument().getLength(),
                    link + "\n", htmlLink);
        } catch (BadLocationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();

        JTextPaneTest chat = new JTextPaneTest();
        frame.add(chat);

        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        chat.chatWithBold("User1", "Hi everyone");
        chat.chatWithBold("User2", "Hey.. Hows it going");

        chat.chatNoBold("User1", "Hi everyone");
        chat.chatNoBold("User2", "Hey.. Hows it going");

        chat.submitALinkWithBold("User1", "http://www.stackru.com");

        frame.setSize(400, 400);

        frame.setVisible(true);

    }

}

1 ответ

Решение

Я просто поиграл, немного искал и нашел следующее решение:

Инициализируйте ваш JTextPane после установки типа контента примерно так:

final String emptyHtml = "<html><body id='bodyElement'></body></html>";
pane.getEditorKit().read(new StringReader(emptyHtml), pane.getDocument(), 0);

После этого инициализируйте следующие два новых поля (для удобства будут использоваться в методах):

this.doc = (HTMLDocument) pane.getDocument();
this.bodyElement = this.doc.getElement("bodyElement");

Теперь вы можете изменить свой метод submitALinkWithBold как это:

final String html =  "<p><b>" + user + ": </b>"
    + "<a href='" + link + "'>" + link + "</a></p>";
doc.insertBeforeEnd(bodyElement, html);

Вы должны быть в состоянии принять эту схему для двух других методов (chatWithBold а также chatNoBold) тоже.

Обратите внимание, что результат не выглядит хорошо (или не работает вообще), пока вы не измените все свои методы. Также обратите внимание, что даже после изменения всех методов, он не похож на ваш оригинальный пример (больший межстрочный интервал, другой шрифт…). Я думаю, что это может быть исправлено путем литья pane.getEditorKit() к HTMLEditorKit и используя его setStyleSheet(…) метод но я не пробовал это.

Другие вопросы по тегам