Swing’s javax.swing.JTextPane
class represents a significant improvement over AWT’s TextArea
. It allows complex combinations of character and paragraph attributes, embedded images and components, and other features that let you build styled text editors. Unfortunately, however, while JTextPane
makes complex things possible, it makes some simple things difficult. Two examples are setting the default font and color.
Figure 1 shows an example of creating an AWT TextArea
that uses a 20-point blue serif font.
import java.awt.TextArea; import java.awt.Frame; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.event.WindowAdapter; import java.awt.Color; import java.awt.Font; import java.awt.BorderLayout; public class Example1 extends WindowAdapter { public Example1() { Frame f = new Frame("TextArea Example"); f.setLayout(new BorderLayout()); // Make a text area, set its font and color, then add it to the frame TextArea text = new TextArea(); Font font = new Font("Serif", Font.ITALIC, 20); text.setFont(font); text.setForeground(Color.blue); f.add(text, BorderLayout.CENTER); // Listen for the user to click the frame's close box f.addWindowListener(this); f.setSize(400, 400); f.show(); } public void windowClosing(WindowEvent evt) { System.exit(0); } public static void main(String[] args) { Example1 instance = new Example1(); } }
TextArea
The code in Figure 1 includes a call to TextArea
‘s setFont(…)
and setForeground(…)
methods, which set the font and color of all of the text in the component. Figure 2 shows a (seemingly) equivalent example using Swing’s JFrame
and JTextPane
classes.
import javax.swing.JTextPane; import javax.swing.JFrame; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.event.WindowAdapter; import java.awt.Color; import java.awt.Font; import java.awt.BorderLayout; public class Example2 extends WindowAdapter { public Example2() { JFrame f = new JFrame("First JTextPane Example"); f.getContentPane().setLayout(new BorderLayout()); // Make a text pane, attempt to set its font and color, then // add it to the frame JTextPane text = new JTextPane(); Font font = new Font("Serif", Font.ITALIC, 20); text.setFont(font); text.setForeground(Color.blue); f.getContentPane().add(text, BorderLayout.CENTER); // Listen for the user to click the frame's close box f.addWindowListener(this); f.setSize(400, 400); f.show(); } public void windowClosing(WindowEvent evt) { System.exit(0); } public static void main(String[] args) { Example2 instance = new Example2(); } }
JTextPane
The code in Figure 2 does not produce the desired result: The text pane uses the default font and color (defined by the current Swing look-and-feel), rather than the font and color passed to the setFont(…)
and setForeground(…)
methods. The explanation for this lies in JTextPane
‘s flexibility. Since each character can have a different font and color, the notion of setting the font and color for all of the text does not make as much sense as it does in the case of the less-flexible TextArea
.
The trick is to set the character attributes for the entire text content. If the text pane is empty, the character attributes will be used for any text entered later. Figure 3 shows an example of this. The static method setJTextPaneFont(…)
contains the logic for updating a JTextPane
‘s attributes from Font
and Color
objects.
import javax.swing.JTextPane; import javax.swing.JFrame; import javax.swing.text.StyledDocument; import javax.swing.text.StyleConstants; import javax.swing.text.MutableAttributeSet; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.event.WindowAdapter; import java.awt.Color; import java.awt.Font; import java.awt.BorderLayout; public class Example3 extends WindowAdapter { public Example3() { JFrame f = new JFrame("Second JTextPane Example"); f.getContentPane().setLayout(new BorderLayout()); // Make a text pane, set its font and color, then add it to the frame JTextPane text = new JTextPane(); Font font = new Font("Serif", Font.ITALIC, 20); setJTextPaneFont(text, font, Color.blue); f.getContentPane().add(text, BorderLayout.CENTER); // Listen for the user to click the frame's close box f.addWindowListener(this); f.setSize(400, 400); f.show(); } /** * Utility method for setting the font and color of a JTextPane. The * result is roughly equivalent to calling setFont(...) and * setForeground(...) on an AWT TextArea. */ public static void setJTextPaneFont(JTextPane jtp, Font font, Color c) { // Start with the current input attributes for the JTextPane. This // should ensure that we do not wipe out any existing attributes // (such as alignment or other paragraph attributes) currently // set on the text area. MutableAttributeSet attrs = jtp.getInputAttributes(); // Set the font family, size, and style, based on properties of // the Font object. Note that JTextPane supports a number of // character attributes beyond those supported by the Font class. // For example, underline, strike-through, super- and sub-script. StyleConstants.setFontFamily(attrs, font.getFamily()); StyleConstants.setFontSize(attrs, font.getSize()); StyleConstants.setItalic(attrs, (font.getStyle() & Font.ITALIC) != 0); StyleConstants.setBold(attrs, (font.getStyle() & Font.BOLD) != 0); // Set the font color StyleConstants.setForeground(attrs, c); // Retrieve the pane's document object StyledDocument doc = jtp.getStyledDocument(); // Replace the style for the entire document. We exceed the length // of the document by 1 so that text entered at the end of the // document uses the attributes. doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, false); } public void windowClosing(WindowEvent evt) { System.exit(0); } public static void main(String[] args) { Example3 instance = new Example3(); } }
JTextPane
The example in Figure 3 will produce 20-point blue text within the JTextPane
.
Of course, JTextPane
is not intended as a direct replacement for the AWT TextArea
. Swing includes a JTextArea
class that mimics TextArea
‘s behavior much more closely, and provides direct source code compatibility. There are, however, reasons to use JTextPane
instead of JTextArea
even in cases where you do not need to support multiple fonts within the text component. For example, JTextArea
does not support embedded images or alternate text alignment.