如何避免JTextPane在初始文本以换行结尾时重置字体设置?
I totally get the frustration here—JTextPane's paragraph-based styling can be tricky when trailing newlines are involved. Let's break down how to solve both your requirements:
Understanding the Root Cause
JTextPane uses a StyledDocument which treats each section separated by paragraph separators (internally, it defaults to using \n as a paragraph break) as a separate paragraph. When you set setText() with trailing newlines, you're creating empty paragraphs at the end. When you move the cursor to the end and type, Swing creates a brand new paragraph that inherits the default document style, not your custom bold/italic red style.
Solution A: Set a Global Default Font for All Paragraphs
This ensures every existing and new paragraph uses your desired style. Instead of just applying attributes to existing text, we'll update the document's default paragraph style:
import javax.swing.*; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import java.awt.*; public class JTextPaneExampleFixedA { public static void main(String args[]) { JFrame frame = new JFrame("JTextPane Global Style Fix"); 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); // Create your custom style SimpleAttributeSet attributeSet = new SimpleAttributeSet(); StyleConstants.setBold(attributeSet, true); StyleConstants.setItalic(attributeSet, true); StyleConstants.setForeground(attributeSet, Color.red); // Apply to existing paragraphs first pane.setSelectionStart(0); pane.setSelectionEnd(pane.getText().length()); pane.setParagraphAttributes(attributeSet, true); // Set as the DEFAULT paragraph style for ALL future paragraphs StyledDocument doc = pane.getStyledDocument(); doc.setDefaultParagraphAttributes(attributeSet); pane.setSelectionStart(pane.getText().length()); JScrollPane scrollPane = new JScrollPane(pane); cp.add(scrollPane, BorderLayout.CENTER); frame.setSize(400, 300); frame.setVisible(true); } }
The key line here is doc.setDefaultParagraphAttributes(attributeSet);—this tells the document to use your custom style for any new paragraphs created when the user types after trailing newlines.
Solution B: Treat the Entire Editable Area as a Single Paragraph
If you want to avoid multiple paragraphs entirely, we need to make sure \n acts as a line break (soft wrap) instead of a paragraph separator. We can do this by using a custom EditorKit that converts newlines to Unicode line separators:
import javax.swing.*; import javax.swing.text.*; import java.awt.*; import java.io.IOException; import java.io.Reader; public class JTextPaneExampleFixedB { public static void main(String args[]) { JFrame frame = new JFrame("JTextPane Single Paragraph Fix"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container cp = frame.getContentPane(); JTextPane pane = new JTextPane(); // Custom EditorKit to treat \n as line breaks, not paragraph breaks pane.setEditorKit(new StyledEditorKit() { @Override public Document createDefaultDocument() { return new DefaultStyledDocument() { @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { // Replace newlines with Unicode line separators str = str.replace("\n", "\u000B"); super.insertString(offs, str, a); } }; } @Override public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException { // Convert newlines to line separators when loading text StringBuilder sb = new StringBuilder(); int c; while ((c = in.read()) != -1) { sb.append(c == '\n' ? '\u000B' : (char) c); } doc.insertString(pos, sb.toString(), null); } }); String welcomeString = String.format("Welcome%n%n%nStranger!%n%n%n"); pane.setText(welcomeString); // Apply custom style to the entire single paragraph 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.setCharacterAttributes(attributeSet, true); pane.setSelectionStart(pane.getText().length()); JScrollPane scrollPane = new JScrollPane(pane); cp.add(scrollPane, BorderLayout.CENTER); frame.setSize(400, 300); frame.setVisible(true); } }
By using \u000B (Unicode line separator) instead of paragraph separators, the entire text becomes one single paragraph. Typing anywhere—even after trailing line breaks—will inherit the same character style.
Why Your Original Code Didn't Work
Your setParagraphAttributes() call only applied to the existing paragraphs created by setText(). When you typed at the end, Swing generated a new paragraph that used the document's default style, not your custom one. Setting the default paragraph style (Solution A) fixes this gap, while Solution B eliminates multiple paragraphs entirely.
Content of the question is from Stack Exchange, asked by Warren

