Enhanced JTextArea with Color Text Support
Published: 2026-06-07
Google AdSense 广告位 (待申请通过后开启)
Java Swing JTextArea with Multi-Color Text Support
This enhanced JTextArea component extends the standard Swing JTextArea by adding support for multi-color text rendering, custom highlighting, and syntax-aware display.
Key features:
• Render text in multiple colors
• Custom keyword highlighting
• Lightweight and easy to integrate
• Compatible with existing Swing applications
• Suitable for logs, terminals, editors, and monitoring tools
package com.util; // Ensure this matches your project's package name
import javax.swing.JTextPane;
import javax.swing.text.*;
import java.awt.Color;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// Disguised as JTextArea, it actually extends JTextPane to support colors
public class JTextArea extends JTextPane {
public JTextArea() {
setEditable(false); // Set to non-editable
}
// Key: Override the append method to perfectly support inline ANSI color codes and Git diff line colors
public void append(String text) {
if (text == null) return;
// 1. Filter out common non-color cursor control codes used in terminals (e.g., clear line [K)
text = text.replaceAll("\u001B\\[[0-9;]*[KkHhGgA-DzZ]", "");
// 2. Unify carriage returns \r into standard newlines
text = text.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
StyledDocument doc = this.getStyledDocument();
String[] lines = text.split("\n", -1); // Ensure trailing empty lines are not ignored
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
// Prioritize checking Git Diff status (line-wide logic)
Color rowBaseColor = null;
String trimmed = line.trim();
// Safely strip any ANSI encoding that might exist at the start of the line for prefix checking
String cleanTrimmed = trimmed.replaceAll("\u001B\\[[0-9;]*m", "");
if (cleanTrimmed.startsWith("+") && !cleanTrimmed.startsWith("+++")) {
rowBaseColor = new Color(0, 140, 0); // Green
} else if (cleanTrimmed.startsWith("-") && !cleanTrimmed.startsWith("---")) {
rowBaseColor = Color.RED; // Red
} else if (cleanTrimmed.startsWith("@@")) {
rowBaseColor = Color.BLUE; // Blue
}
// Parse inline ANSI color codes (e.g., \u001B[31m)
parseAndInsertAnsiLine(doc, line, rowBaseColor);
// If it is not the last line, append the trailing newline character
if (i < lines.length - 1) {
try {
SimpleAttributeSet nextLineSet = new SimpleAttributeSet();
if (rowBaseColor != null) {
StyleConstants.setForeground(nextLineSet, rowBaseColor);
} else {
StyleConstants.setForeground(nextLineSet, Color.BLACK);
}
doc.insertString(doc.getLength(), "\n", nextLineSet);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
// Automatically scroll to the bottom of the text
setCaretPosition(doc.getLength());
}
/**
* Parses ANSI color control codes within a single line and inserts segments sequentially
*/
private void parseAndInsertAnsiLine(StyledDocument doc, String line, Color rowBaseColor) {
// Regex to match \u001B[xxxx m
Pattern pattern = Pattern.compile("\u001B\\[([0-9;]*)m");
Matcher matcher = pattern.matcher(line);
int lastIndex = 0;
// Initial attributes: If there is a line-wide base color (like Git diff), use it. Otherwise, default to black.
SimpleAttributeSet currentAttributes = new SimpleAttributeSet();
Color currentColor = (rowBaseColor != null) ? rowBaseColor : Color.BLACK;
StyleConstants.setForeground(currentAttributes, currentColor);
while (matcher.find()) {
// 1. Insert the regular text before the control code
String textSegment = line.substring(lastIndex, matcher.start());
if (!textSegment.isEmpty()) {
try {
doc.insertString(doc.getLength(), textSegment, currentAttributes);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
// 2. Parse the control code arguments and update the current color state
String ansiCode = matcher.group(1);
currentColor = getAnsiColor(ansiCode, currentColor, rowBaseColor);
currentAttributes = new SimpleAttributeSet();
StyleConstants.setForeground(currentAttributes, currentColor);
lastIndex = matcher.end();
}
// 3. Insert the remaining text of the line
String remainingText = line.substring(lastIndex);
if (!remainingText.isEmpty()) {
try {
doc.insertString(doc.getLength(), remainingText, currentAttributes);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
/**
* Converts ANSI codes into the corresponding Java Color object
*/
private Color getAnsiColor(String ansiCode, Color currentColor, Color rowBaseColor) {
if (ansiCode == null || ansiCode.isEmpty() || "0".equals(ansiCode)) {
// 0 stands for Reset: Roll back to the line-wide base color if it exists, otherwise roll back to black
return (rowBaseColor != null) ? rowBaseColor : Color.BLACK;
}
// Supports multi-parameter combinations like "31;1" (Red and Bold). We split to extract color values.
String[] codes = ansiCode.split(";");
for (String code : codes) {
switch (code) {
case "30": return Color.BLACK;
case "31": return Color.RED; // Common search highlight red
case "32": return new Color(0, 140, 0); // Green
case "33": return Color.ORANGE; // Yellow/Orange
case "34": return Color.BLUE; // Blue
case "35": return Color.MAGENTA; // Magenta
case "36": return Color.CYAN; // Cyan
case "37": return Color.LIGHT_GRAY; // Light Gray
case "39": return (rowBaseColor != null) ? rowBaseColor : Color.BLACK; // Default foreground
// You can expand bright colors (90-97) or background colors here if needed
}
}
return currentColor;
}
// Backward compatibility for the original setText method
@Override
public void setText(String t) {
super.setText(""); // Clear first
if (t != null && !t.isEmpty()) {
append(t); // Trigger colorized append
}
}
public void setLineWrap(boolean b) {
// Placeholder method for structural compatibility
}
}
use:
this.textArea = new JTextArea();
this.textArea.setLineWrap(true);
this.textArea.setFont(new Font("Dialog", 1, 22));
this.textArea.setSelectedTextColor(Color.RED);
String s= "ls -al /usr/local/bin/";
execToTextArea(final String s, final com.util.JTextArea textArea);
INFO Application started
SUCCESS Connected to database
WARNING Memory usage is high
ERROR Connection timeout
DEBUG Loading configuration
Explore More
› How to Send Colored Text to JTextArea Using execToTextArea