Implementare il System.out su una JTextArea

Capita a volte di avere la necessità di visualizzare le chiamate al System.out.println() su un componente grafico invece che nella console predefinita. Come possiamo procedere? Semplicemente java ci mette a disposizione alcune funzionalità che ci permettono di 'dirottare' il System.out su un qualsiai output implementato da noi. In questo breve tips vediamo come eseguire tutto ciò su una JTextArea. Cioè qualsiasi chiamata al System.out verrà visualizzato nella JTextArea invece che nella console predefinita dell'editor di sviluppo che stiamo utlizzando. I metodi che ci permettono di effettuare questa operazione sono due metodi statici della classe java.lang.System:
  • static void setOut(PrintStream out)
  • static void setErr(PrintStream out)
Quindi basta implementare un java.io.PrintStream che scrive su un java.io.OutputStream definito da noi. L'idea è quella di implementare una classe che chiameremo JConsole erede di JTextArea. La classe JConsole al suo interno definisce un PrintStream che scrive su un ByteArrayOutputStream. Quest'ultima classe è un OutputStream che scrive su un array di byte. Vediamo la classe JConsole:
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import javax.swing.JTextArea;

public class JConsole extends JTextArea {

  private PrintStream printStream;

  public JConsole() {
    printStream = new PrintStream(new ConsolePrintStream());
  }

  public PrintStream getPrintStream() {
    return printStream;
  }

  //L' output stream definito da noi
  private class ConsolePrintStream extends ByteArrayOutputStream {
    public synchronized void write(byte[] b, int off, int len) {
      setCaretPosition(getDocument().getLength());
      String str = new String(b);
      append(str.substring(off, len));
    }
  }

}
Nella inner class cioè ConsolePrintStream ridefiniamo solo il metodo write(byte[] b, int off, int len) della superclasse ByteArrayOutputStream, in modo tale che ad ogni flusso di byte che viene scritto sullo stream lo aggiungiamo alla JTextArea tramite il motodo append(). Quindi poi passiamo un'istanza di questa classe al PrintStream (nel costruttore), e forniamo un riferimento di esso esternamente tramite il metodo getPrintStream(). Questa classe è stata modellata in modo tale da essere collegata direttamente ad un qualsiasi PrintStream oltre al System.out, cioè è possibile collagarla ad un qualsiasi output di dati.

Adesso vediamo un esempio con il main che collega la JConsole al System.out visualizzandola in un JFrame. Per verificare l'esecuzione, abbiamo un Thread che ad ogni secondo stampa tramite il metodo System.out.println() il timestamp del sistema (System.currentTimeMillis()) che in questo caso viene visualizzato sulla nostra JConsole:
public static void main(String [] argv) {
  JConsole console = new JConsole();
  console.setEditable(false);

  //Collegamento del System.out alla JConsole
  System.setOut(console.getPrintStream());
  System.setErr(console.getPrintStream());

  //Interfaccia grafica
  JFrame frame = new JFrame("JConsole Demo");
  console.setBorder(new TitledBorder("Console"));
  frame.getContentPane().add(new JScrollPane(console));
  frame.setSize(500,400);
  frame.setVisible(true);


  System.out.println("Avvio del thread...");
  //Thread che stampa dopo ogni secondo un messaggio con il timestamp
  Thread thread = new Thread(new Runnable() {
    public void run() {
      try {
        while(true) {
          Thread.sleep(1000);
          System.out.println("Timestamp del sistema :"+System.currentTimeMillis());
        }
      }
      catch(InterruptedException ex) {}
    }
  });
  thread.start();
}
Da notare che JConsole è comunque una JTextArea è quindi possiamo anche modificare il font, lo sfondo, ed in più possiamo aggiungere magari anche un popup menu per la gestione della clipboard con le funzioni copia e cancella. Questa è l' esecuzione del main:

JConsole Demo

Altri link che potrebbero interessarti
  • Utilizzare un JButton in Java Swing
  • Utilizzare HTML in componenti Java Swing
  • Numeri casuali in java
  • Modalità Full Screen Exclusive in java
  • Leggere un file di testo in java
  • Le variabili atomiche in java
  • Le classi anonime
  • Java Regex
  • Java Database MySql
  • Java Cursor Mouse
  • Import Static Java
  • Implementare un Singleton
  • Implementare un KeyListener in java Swing
  • Il costrutto if in java
  • Il costrutto foreach in java
  • Il blocco static
  • Creare una ToolBar in Java Swing
  • Chiudere le applicazioni Java Swing
  • Bordo con titolo in Java Swing
  • Background Image per componenti Java Swing