I'm trying to get the html formatted content from my JTextPane
.
Problem is that when I insert the text with a specified AttributeSet
, the content text is not output when trying to write it out to a file, but the styling is.
I'm not sure if this is to do with how I am inserting the text or how I'm attempting to write it out to a file.
Here is an example:
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import java.awt.BorderLayout;
import java.io.*;
import java.awt.Color;
public class SOExample extends JFrame
{
public static void main (String[] args)
{
SwingUtilities.invokeLater(
new Runnable()
{
@Override
public void run()
{
SOExample aFrame = new SOExample();
aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
aFrame.setVisible(true);
}
}
);
}
public SOExample()
{
initComponents();
addText("This is my plain text", null);
SimpleAttributeSet BOLD = new SimpleAttributeSet();
StyleConstants.setBold(BOLD, true);
StyleConstants.setForeground(BOLD, Color.BLUE);
addText("This is my BLUE BOLD text",BOLD);
outputHTMLfile();
}
private void initComponents()
{
this.setBounds(300,300,300,300);
jtp = new JTextPane();
jtp.setContentType("text/html");
jsp = new JScrollPane();
JPanel jp = new JPanel(new BorderLayout());
jp.add(jtp);
jsp.add(jp);
jsp.setViewportView(jp);
this.add(jsp, BorderLayout.CENTER);
}
private void addText(String text, SimpleAttributeSet attr)
{
try
{
HTMLDocument doc = (HTMLDocument)jtp.getDocument();
doc.insertString(doc.getLength(), text +"\n", attr);
}
catch (BadLocationException blex)
{
blex.printStackTrace();
}
}
private void outputHTMLfile()
{
File f = new File("C:\\Temp", "TestFile.html");
try
{
BufferedOutputStream br = new BufferedOutputStream(new FileOutputStream(f));
HTMLEditorKit kit = new HTMLEditorKit();
kit.write(br, (HTMLDocument)jtp.getDocument(), 0, ((HTMLDocument)jtp.getDocument()).getLength() );
}
catch (Exception e)
{
e.printStackTrace();
}
}
private JTextPane jtp;
private JScrollPane jsp;
}
This will give me the output file with html like this
<html>
<head>
</head>
<body>
<p style="margin-top: 0">
This is my plain text
</p>
<p style="margin-top: 0">
<b><font color="#0000ff"><p>
</font></b> </p>
</body>
</html>
As you can see this is missing the text "This is my BLUE BOLD text"
but it will show correctly in the frame.
I've also tried writing jtp.getText()
directly to the file and get the same result.
While I was testing your code, I noticed something strange. If you look closely at that last string on the JTextPane (This is my BLUE BOLD text), although it shows in bold, it is not quite in the same font as the previous text.
That's an unequivocal sign that some attributes have been lost. Notice also that the HTML generated after inserting that string (the one posted above) is missing a </p>
tag: a new paragraph is opened right after the font tag. Again, something has been lost in the way.
So, what's going on here? Well, when you pass attributes to the insertString method, these will overwrite any already existing attributes. What you have to do is, before insertion, merge those attributes with the new bold and colour ones. In effect, you have to slightly change the code for the constructor:
public SOExample() {
initComponents();
addText("This is my plain text", null);
//Retrieve existing attributes.
SimpleAttributeSet previousAttribs = new SimpleAttributeSet
(jtp.getInputAttributes()
.copyAttributes());
SimpleAttributeSet BOLD = new SimpleAttributeSet();
StyleConstants.setBold (BOLD, true);
StyleConstants.setForeground (BOLD, Color.BLUE);
//Merge new attributes with existing ones.
previousAttribs.addAttributes (BOLD);
//Insert the string and apply merged attributes.
addText ("This is my BLUE BOLD text", previousAttribs);
outputHTMLfile();
}
See the difference in font? As for the getInputAttributes().coppyAttributes() in the code, it gives the current set of attributes that will be used in any subsequent insertion. Which is pretty much what we need.
You may be wondering what attributes could possibly exist if no text has been inserted yet. In short, every element in the text that is just that, text, will be identified by a special internal "tag" called content. This tag is stored as an attribute. And it is the loss of this attribute what was wreaking havoc here.
Hope this helps!