Getting html from JTextPane - missing content text - java

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!

Related

How can I prevent JTextPane from resetting font settings if the initial text ends with a linefeed?

I've run into a problem with JTextPane. The code I am working with sets a number of font attributes, such as BOLD, ITALIC, etc. But if the initial text ends with a single linefeed, and the user clicks on the last line, or is sent to the last line, the default font settings appear for any additional text the user types.
Specifically, this text works as I would expect: jTextPane.setText(String.format("Test This"));.
This text does not:
jTextPane.setText(String.format("Test This%n%n%n"));
I think that JTextPane may consider this to be a new paragraph.
If so, I would like to either
a.) Know how to set a universal font that applies across the entire JTextPane instance's paragraphs.
or
b.) tell the JTextPane instance to consider all of its editable area to be one paragraph.
Here is a toy program to show you what I mean. If you run this, and start typing at the end of the text the font will be whatever the default is for your Swing implementation.
I have also tried setting the document model of the JTextPane and using a Font instance in the JTextPane constructor. The results are the same.
Another alternative is to use a JTextArea instance instead, but this is very complex code and I hesitate to make a change that may break some other area of the application than the one I am working in.
import javax.swing.*;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import java.awt.*;
public class JTextPaneExampleOne {
public static void main(String args[]) {
JFrame frame = new JFrame("JTextPane Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = frame.getContentPane();
JTextPane pane = new JTextPane();
String welcomeString = String.format("Welcome%n%n%nStranger!%n%n%n");
pane.setText( welcomeString );
pane.invalidate();
SimpleAttributeSet attributeSet = new SimpleAttributeSet();
StyleConstants.setBold(attributeSet, true);
StyleConstants.setItalic(attributeSet, true);
StyleConstants.setForeground(attributeSet, Color.red);
pane.setSelectionStart( 0 );
pane.setSelectionEnd( pane.getText().length() );
pane.setParagraphAttributes( attributeSet, true );
pane.setSelectionStart( pane.getText().length() );
pane.validate();
JScrollPane scrollPane = new JScrollPane(pane);
cp.add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
a.) Know how to set a universal font that applies across the entire JTextPane instance's paragraphs.
In this case, you might be able to use JTextPane#setLogicalStyle(Style):
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class JTextPaneExampleOne2 {
public Component makeUI() {
JTextPane pane = new JTextPane();
Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
Style body = pane.getStyledDocument().addStyle("body", def);
StyleConstants.setBold(body, true);
StyleConstants.setItalic(body, true);
StyleConstants.setForeground(body, Color.RED);
pane.setLogicalStyle(body);
String welcomeString = String.format("Welcome%n%n%nStranger!%n%n%n");
pane.setText(welcomeString);
// SimpleAttributeSet attributeSet = new SimpleAttributeSet();
// StyleConstants.setBold(attributeSet, true);
// StyleConstants.setItalic(attributeSet, true);
// StyleConstants.setForeground(attributeSet, Color.RED);
//
// pane.setSelectionStart(0);
// pane.setSelectionEnd(pane.getText().length());
// pane.setParagraphAttributes(attributeSet, true);
// pane.setSelectionStart(pane.getText().length());
return new JScrollPane(pane);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame("JTextPane Example");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new JTextPaneExampleOne2().makeUI());
f.setSize(400, 400);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}

change specific text color in java

i am wondering how can i change a specific text color in a sentence?
lets say HELLO WORLD...i wanted to change the WORLD into red color without altering the font color of HELLO..same exact thing on how to change the WORLD in to bold
i wanted to set these string in to a jtextarea but all i can find is something like this
JTextArea textbox = new JTextArea("hello world");
textbox.setForeground(Color.red)
these makes the whole sentence into red instead of only making WORLD into red?
Have a look at this this from the Oracle documentation on text components. A JTextArea will accept styling, but it will always apply styling across its entire contents. However, if you were to use a JTextPane, you could create any styling you wanted in your text using HTML.
Code to back up assertion:
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.html.HTMLEditorKit;
public class StyleTestApp {
public static void main(final String[] args) {
final JFrame f = new JFrame("test");
//f.getContentPane().add(new JTextArea("<html>HELLO <font size=\"3\" face=\"verdana\" color=\"red\">WORLD</font></html>"));
final JTextPane p = new JTextPane();
// the HTMLEditorKit is not enabled by default in the JTextPane class.
p.setEditorKit(new HTMLEditorKit());
p.setText("<html>HELLO <font size=\"3\" face=\"verdana\" color=\"red\">WORLD</font></html>");
f.getContentPane().add(p);
f.pack();
f.setVisible(true);
}
}

change font of specific lines in JTextArea

hi there ı am working on a chat application and i want that user can change the font which he/she is writing. there is a setFont() function but it changes font of all strings in the TextArea. so i just want to change only my font.i appreciated if you can help me.
well then i guess i must learn a litte HTML
I wouldn't use HTML. I find it easier to just use attributes when dealing with a text pane. Attributes are much easier to change then trying to manipulate HTML.
SimpleAttributeSet green = new SimpleAttributeSet();
StyleConstants.setFontFamily(green, "Courier New Italic");
StyleConstants.setForeground(green, Color.GREEN);
// Add some text
try
{
textPane.getDocument().insertString(0, "green text with Courier font", green);
}
catch(Exception e) {}
You should work with JTextPane. JTextPane allows you to use HTML. Check the following example:
this.text_panel = new JTextPane();
this.text_panel.setContentType("text/html");
this.text_panel.setEditable(false);
this.text_panel.setBackground(this.text_background_color);
this.text_panel_html_kit = new HTMLEditorKit();
this.text_panel.setEditorKit(text_panel_html_kit);
this.text_panel.setDocument(new HTMLDocument());
Here you are enabling HTMLEditorKit, which will allow you to use HTML in your TextPane. Here is another peice of code, where you can add colored text to the panel:
public void append(String line){
SimpleDateFormat date_format = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
line = "<div><font size=3 color=GRAY>[" + date_format.format(date) + "]</font><font size=3 color=BLACK>"+ line + "</font></div>";
try {
this.text_panel_html_kit.insertHTML((HTMLDocument) this.text_panel.getDocument(), this.text_panel.getDocument().getLength(), line, 0, 0, null);
} catch (Exception e) {
e.printStackTrace();
}
}
Hope this helps,
Serhiy.
You can't do that with JTextArea, but you can do it with its fancier cousin, JTextPane. It's unfortunately not trivial; you can learn about this class here.
A variety of Swing components will render basic HTML (version 3.2), including JLabel & JEditorPane. For further details see How to Use HTML in Swing Components in the Java Tutorial.
Here is a simple example using the latter.
import java.awt.*;
import javax.swing.*;
class ShowFonts {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GraphicsEnvironment ge = GraphicsEnvironment.
getLocalGraphicsEnvironment();
String[] fonts = ge.getAvailableFontFamilyNames();
String pre = "<html><body style='font-size: 20px;'><ul>";
StringBuilder sb = new StringBuilder(pre);
for (String font : fonts) {
sb.append("<li style='font-family: ");
sb.append(font);
sb.append("'>");
sb.append(font);
}
JEditorPane ep = new JEditorPane();
ep.setContentType("text/html");
ep.setText(sb.toString());
JScrollPane sp = new JScrollPane(ep);
Dimension d = ep.getPreferredSize();
sp.setPreferredSize(new Dimension(d.width,200));
JOptionPane.showMessageDialog(null, sp);
}
});
}
}

Setting text color with a JColorChooser

I'm trying to make a text editor with a JTextPane, but i'm having trouble with setting the selected texts color. Here is the best could come up with (but, obviously, not working):
JMenuItem button = new JMenuItem("Set Color");
toolbar.add(button);
button.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent e) {
Color c = JColorChooser.showDialog(frame,"Choose a color", getBackground());
textPane.getSelectedText().StyledEditorKit.ForegroundAction("color",c);
}
});
Any suggestions on how to get that to work? Or a better method of doing it?
Thanks
getSelectedText() just returns a normal string containing the selected text; you cannot use it to modify the attributes of the text.
I would start by using SimpleAttributeSet and StyleConstants to generate the colour attribute, then apply it to the selected portion of your text:
SimpleAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setForeground(attr, c);
textPane.setCharacterAttributes(attr, false);

How can I display red text in a JTextArea?

I want to show error(text) in result in red color after compiling exec file
and display it in textarea of gui using swing in java.
A normal JTextArea doesn't support fancy things like different colors of text. However, there are similar components that do. See http://java.sun.com/docs/books/tutorial/uiswing/components/text.html
JEditorPane can get content formatted in HTML. The official Sun tutorial also gives some insight:
The JTextArea class provides a component that displays multiple lines of text and optionally allows the user to edit the text. If you need to obtain only one line of input from the user, you should use a text field. If you want the text area to display its text using multiple fonts or other styles, you should use an editor pane or text pane. If the displayed text has a limited length and is never edited by the user, use a label.
Here's a quick example of adding text to a JEditorPane using AttributeSet and StyleConstants.
This brings up a little frame with a JEditorPane and you can use it to add text of lots of colors without using HTML.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.text.*;
import javax.swing.border.*;
public class TextColor extends JFrame implements ActionListener {
JTextPane myTextPane;
JTextArea inputTextArea;
public TextColor() {
super();
JPanel temp = new JPanel(new BorderLayout());
inputTextArea = new JTextArea();
JButton btn = new JButton("Add");
btn.addActionListener(this);
temp.add(btn, BorderLayout.SOUTH);
temp.add(inputTextArea, BorderLayout.NORTH);
this.getContentPane().add(temp, BorderLayout.SOUTH);
myTextPane = new JTextPane();
myTextPane.setBorder(new EtchedBorder());
this.getContentPane().add(myTextPane, BorderLayout.CENTER);
this.setSize(600, 600);
this.setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Color newTextColor = JColorChooser.showDialog(this, "Choose a Color", Color.black);
//here is where we change the colors
SimpleAttributeSet sas = new SimpleAttributeSet(myTextPane.getCharacterAttributes());
StyleConstants.setForeground(sas, newTextColor);
try {
myTextPane.getDocument().insertString(myTextPane.getDocument().getLength(),
inputTextArea.getText(), sas);
} catch (BadLocationException ble) {
ble.printStackTrace();
}
}
public static void main(String args[]) {
new TextColor();
}
}
Smita,
take care to paste snippet of your code so that one can understand where exactly problem is or help is required.
Coming to your problem,
To the best of my knowledge, there is no way to set different colors for different text elements in textArea in java. You can set only one color for all.
Alternative is to use JTextPane.
See if following code helps your cause.
String text = "Some Text..."; //This can be any piece of string in your code like
output of your program...
JTextPane myTextPane = new JTextPane();
SimpleAttributeSet sas = new SimpleAttributeSet(myTextPane.getCharacterAttributes());
// As what error you were referring was not clear, I assume there is some code in your
program which pops out some error statement. For convenience I use Exception here..
if( text.contains("Exception") ) //Checking if your output contains Exception...
{
StyleConstants.setForeground(sas, Color.red); //Changing the color of
StyleConstants.setItalic(sas, true);
try
{
myTextPane.getDocument().insertString
(
myTextPane.getDocument().getLength(),
text + "\n",
sas
);
}
catch( BadLocationException ble )
{
text.append(ble.getMessage());
}
}
else
{
StyleConstants.setForeground(sas, Color.GREEN);
try
{
myTextPane.getDocument().insertString
(
myTextPane.getDocument().getLength(),
text + "\n",
sas
);
}
catch(BadLocationException ble)
{
text.append(ble.getMessage());
}
}
I guess this will solve your problem with few modifications.
Thanks.
Sushil

Categories