Cómo configurar el flujo de salida en TextArea
Estoy intentando crear un panel GUI para un programa y me gustaría que todo lo que normalmente se imprimiría en mi símbolo del sistema se imprima en un objeto TextArea. Tengo el panel GUI formateado en su mayor parte, aunque no puedo imprimir el texto en TextArea, aquí está mi archivo:
package guipanel;
import javax.swing.*;
import java.awt.*;
import java.io.*;
/**
*
* @author Dan
*/
public class GUIPanel extends JFrame {
public GUIPanel() {
initComponents();
}
private void setOutputStream(boolean catchErrors) {
System.setOut(aPrintStream);
setVisible(true);
requestFocus();
if (catchErrors) {
System.setErr(aPrintStream);
}
}
private void addTabs(JTabbedPane jTabbedPane1) {
JPanel jPanel1 = new JPanel();
JPanel jPanel2 = new JPanel();
JPanel jPanel3 = new JPanel();
JPanel jPanel4 = new JPanel();
jTabbedPane1.add("Main", textArea1);
jTabbedPane1.add("Commands", jPanel);
jTabbedPane1.add("Rules", jPanel1);
jTabbedPane1.add("Links", jPanel2);
jTabbedPane1.add("Information", jPanel3);
jTabbedPane1.add("Shutdown", jPanel4);
setOutputStream(true);
}
@SuppressWarnings("unchecked")
private void initComponents() {
textArea1 = new java.awt.TextArea();
jTabbedPane1 = new javax.swing.JTabbedPane();
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
jMenu2 = new javax.swing.JMenu();
textArea1.setPreferredSize(new java.awt.Dimension(432, 343));
textArea1.getAccessibleContext().setAccessibleParent(jTabbedPane1);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Evolution-X 639");
setBounds(new java.awt.Rectangle(0, 0, 400, 450));
setResizable(false);
getContentPane().setLayout(new java.awt.FlowLayout());
addTabs(jTabbedPane1);
getContentPane().add(jTabbedPane1);
jMenu1.setText("File");
jMenuBar1.add(jMenu1);
jMenu2.setText("Edit");
jMenuBar1.add(jMenu2);
setJMenuBar(jMenuBar1);
pack();
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(GUIPanel.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GUIPanel().setVisible(true);
}
});
}
private JMenu jMenu1;
private JMenu jMenu2;
private JMenuBar jMenuBar1;
private JTabbedPane jTabbedPane1;
private TextArea textArea1;
private JPanel jPanel = new JPanel();
private PrintStream aPrintStream =
new PrintStream(
new FilterOutputStream(
new ByteArrayOutputStream()));
}
Necesita redirigir el flujo de impresión a un flujo de salida que pueda controlar...
Este es un ejemplo de concepto que desarrollé para una aplicación en la que estoy trabajando. Usamos esto para abrir la consola de salida cuando se está ejecutando en los sitios de los usuarios para que podamos ver qué se envía a la salida estándar... hasta que arreglemos nuestro registro;)
Básicamente, coloca una configuración personalizada OutputStream
entre el flujo de impresión y la consola para capturar la salida, pero aún permite que el contenido se imprima en la consola. Esto es útil si ejecuta el programa desde la línea de comandos o IDE. Podrías poner un interruptor para detener esto si quisieras...
public class TestRedirect {
public static void main(String[] args) {
new TestRedirect();
}
public TestRedirect() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
CapturePane capturePane = new CapturePane();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(capturePane);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
PrintStream ps = System.out;
System.setOut(new PrintStream(new StreamCapturer("STDOUT", capturePane, ps)));
System.out.println("Hello, this is a test");
System.out.println("Wave if you can see me");
}
});
}
public class CapturePane extends JPanel implements Consumer {
private JTextArea output;
public CapturePane() {
setLayout(new BorderLayout());
output = new JTextArea();
add(new JScrollPane(output));
}
@Override
public void appendText(final String text) {
if (EventQueue.isDispatchThread()) {
output.append(text);
output.setCaretPosition(output.getText().length());
} else {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
appendText(text);
}
});
}
}
}
public interface Consumer {
public void appendText(String text);
}
public class StreamCapturer extends OutputStream {
private StringBuilder buffer;
private String prefix;
private Consumer consumer;
private PrintStream old;
public StreamCapturer(String prefix, Consumer consumer, PrintStream old) {
this.prefix = prefix;
buffer = new StringBuilder(128);
buffer.append("[").append(prefix).append("] ");
this.old = old;
this.consumer = consumer;
}
@Override
public void write(int b) throws IOException {
char c = (char) b;
String value = Character.toString(c);
buffer.append(value);
if (value.equals("\n")) {
consumer.appendText(buffer.toString());
buffer.delete(0, buffer.length());
buffer.append("[").append(prefix).append("] ");
}
old.print(c);
}
}
}
Actualizado con un ejemplo funcional. Pruebe en Windows 7, Java 6 y Mac OS Lion Java 7
La solución de MadProgrammer es realmente genial y basé la mía en la suya. Sin embargo, como señaló Loopkin, no trata con caracteres especiales (para ser precisos, falla en todos los caracteres que no son ASCII).
La solución de Loopkin no funcionó para mí, pero finalmente se me ocurrieron 2 soluciones que funcionaron.
Solución 1: maneja cada carácter de 1 byte (hasta U+00FF)
Esta sencilla solución maneja todos los caracteres hasta U+00FF (cada carácter de 1 byte). Todo es idéntico a MadProgrammer, excepto write()
que se define como:
@Override
public void write(int b) throws IOException {
buffer.append(Character.toChars((b + 256) % 256));
if ((char) b == '\n') {
textArea.append(str);
textArea.setCaretPosition(textArea.getDocument().getLength());
buffer.delete(0, buffer.length());
}
old.write(b);
}
No he puesto el prefijo porque no lo necesitaba.
Solución 2: maneja cada objeto como una salida estándar
Al final, decidí incluir todos los caracteres, así que terminé extendiéndolos directamente PrintStream
y también puse de nuevo el prefijo/sangría. El problema es que no pude anular el método privado write(String s)
, así que anulé todos los print()
métodos:
public class PrintStreamCapturer extends PrintStream {
private JTextArea text;
private boolean atLineStart;
private String indent;
public PrintStreamCapturer(JTextArea textArea, PrintStream capturedStream, String indent) {
super(capturedStream);
this.text = textArea;
this.indent = indent;
this.atLineStart = true;
}
public PrintStreamCapturer(JTextArea textArea, PrintStream capturedStream) {
this(textArea, capturedStream, "");
}
private void writeToTextArea(String str) {
if (text != null) {
synchronized (text) {
text.setCaretPosition(text.getDocument().getLength());
text.append(str);
}
}
}
private void write(String str) {
String[] s = str.split("\n", -1);
if (s.length == 0)
return;
for (int i = 0; i < s.length - 1; i++) {
writeWithPotentialIndent(s[i]);
writeWithPotentialIndent("\n");
atLineStart = true;
}
String last = s[s.length - 1];
if (!last.equals("")) {
writeWithPotentialIndent(last);
}
}
private void writeWithPotentialIndent(String s) {
if (atLineStart) {
writeToTextArea(indent + s);
atLineStart = false;
} else {
writeToTextArea(s);
}
}
private void newLine() {
write("\n");
}
@Override
public void print(boolean b) {
synchronized (this) {
super.print(b);
write(String.valueOf(b));
}
}
@Override
public void print(char c) {
synchronized (this) {
super.print(c);
write(String.valueOf(c));
}
}
@Override
public void print(char[] s) {
synchronized (this) {
super.print(s);
write(String.valueOf(s));
}
}
@Override
public void print(double d) {
synchronized (this) {
super.print(d);
write(String.valueOf(d));
}
}
@Override
public void print(float f) {
synchronized (this) {
super.print(f);
write(String.valueOf(f));
}
}
@Override
public void print(int i) {
synchronized (this) {
super.print(i);
write(String.valueOf(i));
}
}
@Override
public void print(long l) {
synchronized (this) {
super.print(l);
write(String.valueOf(l));
}
}
@Override
public void print(Object o) {
synchronized (this) {
super.print(o);
write(String.valueOf(o));
}
}
@Override
public void print(String s) {
synchronized (this) {
super.print(s);
if (s == null) {
write("null");
} else {
write(s);
}
}
}
@Override
public void println() {
synchronized (this) {
newLine();
super.println();
}
}
@Override
public void println(boolean x) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(char x) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(int x) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(long x) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(float x) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(double x) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(char x[]) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(String x) {
synchronized (this) {
print(x);
newLine();
super.println();
}
}
@Override
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
super.println();
}
}
}
Eliminé el Consumer
aspecto para hacerlo simple, pero todo lo que realmente se necesita está aquí. Así es como usé esta clase:
System.setOut(new PrintStreamCapturer(logTextArea, System.out));
System.setErr(new PrintStreamCapturer(logTextArea, System.err, "[ERROR] "));
Me gusta la respuesta de MadProgrammer pero no creo que funcione para caracteres UTF-8.
En su lugar, haría que StreamCapturer extendiera ByteArrayOutputStream y lo usara como implementación de escritura.
@Override
public void write(int b){
if ('\n' == (char) b) {
consumer.appendText(toString());
reset();
}
else {
super.write(b);
}
old.write(b);
}
Me estoy saltando la parte del prefijo porque no la necesito en mi implementación. Gracias por el código, ¡ha sido de gran ayuda!