2010-12-14 23 views
9

Tengo una clase (que se muestra a continuación) que se extiende JPanel y contiene un JTextPane. Quiero redirigir System.out y System.err a mi JTextPane. Mi clase no parece funcionar. Cuando lo ejecuto, redirige las impresiones del sistema, pero no se imprimen en mi JTextPane. ¡Por favor ayuda!Redireccionamiento System.out a JTextPane

Nota: Las llamadas solo se redirigen cuando se inicia la aplicación. Pero en cualquier momento después del lanzamiento, las llamadas System.out no se redirigen al JTextPane. (es decir, si coloco un System.out.prinln(); en la clase, se ejecutará, pero si se coloca en un actionListener para su uso posterior, no se redirige).

public class OSXConsole extends JPanel { 
    public static final long serialVersionUID = 21362469L; 

    private JTextPane textPane; 
    private PipedOutputStream pipeOut; 
    private PipedInputStream pipeIn; 


    public OSXConsole() { 
     super(new BorderLayout()); 
     textPane = new JTextPane(); 
     this.add(textPane, BorderLayout.CENTER); 

     redirectSystemStreams(); 

     textPane.setBackground(Color.GRAY); 
     textPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 

    } 


    private void updateTextPane(final String text) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       Document doc = textPane.getDocument(); 
       try { 
        doc.insertString(doc.getLength(), text, null); 
       } catch (BadLocationException e) { 
        throw new RuntimeException(e); 
       } 
       textPane.setCaretPosition(doc.getLength() - 1); 
      } 
     }); 
    } 


    private void redirectSystemStreams() { 
     OutputStream out = new OutputStream() { 
     @Override 
     public void write(final int b) throws IOException { 
      updateTextPane(String.valueOf((char) b)); 
     } 

     @Override 
     public void write(byte[] b, int off, int len) throws IOException { 
      updateTextPane(new String(b, off, len)); 
     } 

     @Override 
     public void write(byte[] b) throws IOException { 
      write(b, 0, b.length); 
     } 
     }; 

     System.setOut(new PrintStream(out, true)); 
     System.setErr(new PrintStream(out, true)); 
    } 


} 
+0

He borrado mi respuesta porque era incorrecta. – jjnguy

+0

¿Ve algunas llamadas redirigidas y otras no? – jjnguy

+0

solo las llamadas desde el interior de la clase OSXConsole se imprimen en el JTextPane. – Jakir00

Respuesta

7

Hilo arroyos siempre me confunden, por lo que mi solución Mensaje de consola no los usa. De todos modos, aquí está mi intento de una consola que utiliza flujos de tuberías. Un par de diferencias:

a) usa un JTextArea porque un JTextArea es más eficiente que un JTextPane solo para mostrar texto. Por supuesto, si tiene la intención de agregar atributos al texto, entonces necesita un panel de texto.

b) esta solución utiliza subprocesos. Estoy seguro de que leí en alguna parte que esto era necesario para evitar el bloqueo de la salida. De todos modos, funciona en mi caso de prueba simple.

import java.io.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.text.*; 

public class Console implements Runnable 
{ 
    JTextArea displayPane; 
    BufferedReader reader; 

    private Console(JTextArea displayPane, PipedOutputStream pos) 
    { 
     this.displayPane = displayPane; 

     try 
     { 
      PipedInputStream pis = new PipedInputStream(pos); 
      reader = new BufferedReader(new InputStreamReader(pis)); 
     } 
     catch(IOException e) {} 
    } 

    public void run() 
    { 
     String line = null; 

     try 
     { 
      while ((line = reader.readLine()) != null) 
      { 
//    displayPane.replaceSelection(line + "\n"); 
       displayPane.append(line + "\n"); 
       displayPane.setCaretPosition(displayPane.getDocument().getLength()); 
      } 

      System.err.println("im here"); 
     } 
     catch (IOException ioe) 
     { 
      JOptionPane.showMessageDialog(null, 
       "Error redirecting output : "+ioe.getMessage()); 
     } 
    } 

    public static void redirectOutput(JTextArea displayPane) 
    { 
     Console.redirectOut(displayPane); 
     Console.redirectErr(displayPane); 
    } 

    public static void redirectOut(JTextArea displayPane) 
    { 
     PipedOutputStream pos = new PipedOutputStream(); 
     System.setOut(new PrintStream(pos, true)); 

     Console console = new Console(displayPane, pos); 
     new Thread(console).start(); 
    } 

    public static void redirectErr(JTextArea displayPane) 
    { 
     PipedOutputStream pos = new PipedOutputStream(); 
     System.setErr(new PrintStream(pos, true)); 

     Console console = new Console(displayPane, pos); 
     new Thread(console).start(); 
    } 

    public static void main(String[] args) 
    { 
     JTextArea textArea = new JTextArea(); 
     JScrollPane scrollPane = new JScrollPane(textArea); 

     JFrame frame = new JFrame("Redirect Output"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(scrollPane); 
     frame.setSize(200, 100); 
     frame.setVisible(true); 

     Console.redirectOutput(textArea); 
     final int i = 0; 

     Timer timer = new Timer(1000, new ActionListener() 
     { 
      public void actionPerformed(ActionEvent e) 
      { 
       System.out.println(new java.util.Date().toString()); 
       System.err.println(System.currentTimeMillis()); 
      } 
     }); 
     timer.start(); 
    } 
} 
7

Message Console clase hace esto para usted.

Editar:

Aquí es un simple clase de prueba:

import java.io.*; 
import java.awt.*; 
import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.text.*; 

public class MessageConsoleTest 
{ 
    public static int counter; 

    public static void main(String[] args) 
     throws Exception 
    { 
     JTextComponent textComponent = new JTextPane(); 
     JScrollPane scrollPane = new JScrollPane(textComponent); 

     JFrame.setDefaultLookAndFeelDecorated(true); 
     JFrame frame = new JFrame("Message Console"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(scrollPane); 
     frame.setSize(400, 120); 
     frame.setVisible(true); 

     MessageConsole console = new MessageConsole(textComponent); 
     console.redirectOut(); 
     console.redirectErr(Color.RED, null); 

     Timer timer = new Timer(1000, new java.awt.event.ActionListener() 
     { 
      public void actionPerformed(java.awt.event.ActionEvent e) 
      { 
       System.out.println(new java.util.Date().toString()); 
      } 
     }); 
     timer.start(); 

     Thread.sleep(750); 

     Timer timer2 = new Timer(1000, new java.awt.event.ActionListener() 
     { 
      public void actionPerformed(java.awt.event.ActionEvent e) 
      { 
       System.err.println("Error Message: " + ++counter); 
      } 
     }); 
     timer2.start(); 
    } 
} 
+1

Intenté esto, pero parece no funcionar en absoluto. – Jakir00

+0

@Jacob, si tiene un SSCCE simple (http://sscce.org) que demuestra que no funciona, puede usar la página "Contáctenos" del sitio web para enviarme un código para que lo vea. – camickr

+0

Funciona si lo usa bien. Sin embargo, para obtener resultados en vivo, deberá colocar cualquier tarea de larga duración en un SwingWorker. – CaffeineToCode