Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JTextPane/JEditorPane and weird text issue

I am creating a simple chat program that I want to eventually show html links. My problem right now is that I can't get the text to appear next to the users name as I want it to.

I want the user's name to be bold, and the text to appear right next to it, but for some reason the non bolded text appears centered.

If I do not bold the users name, it works fine. The top two are how it appears when I have the names bolded, the middle is when the name is not bolded, the bottom shows a hyperlink I want it to appear like the middle two, but with the names bolded.

enter image description here

Here is the code, what am I doing wrong? Note that I tried replacing JTextPane with JEditorPane and the same thing happens.

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) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
            
                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.stackoverflow.com");

                frame.setSize(400, 400);

                frame.setVisible(true);
            }
        });


    }

}
like image 975
mainstringargs Avatar asked Jul 09 '12 22:07

mainstringargs


1 Answers

I just played and searched around a bit and found the following solution:

Initialize your JTextPane after setting the content type with something like this:

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

After that initialize the following two new fields (will be used in the methods, just for convenience):

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

Now you can change your method submitALinkWithBold like this:

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

You should be able to adopt this scheme to the other two methods (chatWithBold and chatNoBold) too.

Note that the result does not look good (or does not work at all) until you change all your methods. Also note that even after changing all methods, it does not look like your original example (larger line spacing, other font…). I think this could be fixed by casting pane.getEditorKit() to a HTMLEditorKit and using its setStyleSheet(…) method but I did not try this.

like image 133
siegi Avatar answered Nov 05 '22 18:11

siegi