2010-12-14 72 views
9

我有一个类(如下所示),它扩展了JPanel并包含一个JTextPane。我想将System.outSystem.err重定向到我的JTextPane。我的班似乎没有工作。当我运行它时,它会重定向系统打印,但它们不打印到我的JTextPane。请帮忙!将System.out重定向到JTextPane

注意:调用只在应用程序启动时重定向。但是在启动后的任何时间,System.out调用都不会重定向到JTextPane。 (即,如果我在课堂中放置了System.out.prinln();,它将被调用,但是如果将它放置在actionListener中供以后使用,则不会重定向)。

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

我删除了我的答案,因为它是错误的。 – jjnguy 2010-12-14 21:06:23

+0

你是否看到一些呼叫被重定向? – jjnguy 2010-12-14 21:06:52

+0

只有OSXConsole类内的调用才会打印到JTextPane。 – Jakir00 2010-12-14 21:08:38

回答

7

管道流总是让我困惑,这就是为什么我的消息控制台解决方案不使用它们。无论如何,这里是我在使用管道流的控制台上的尝试。有几点不同:

a)它使用JTextArea,因为JTextArea比JTextPane更加高效,仅用于显示文本。当然,如果你打算为文本添加属性,那么你需要一个文本窗格。

b)此解决方案使用线程。我确信我在某处读到这是防止输出阻塞所必需的。无论如何,它适用于我的简单测试用例。

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 class为你做这个。

编辑:

下面是一个简单的测试类:

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

我试过了,但它似乎并没有工作。 – Jakir00 2010-12-14 21:52:44

+0

@Jacob,如果你有一个简单的SSCCE(http://sscce.org),说明它无法工作,你可以使用网站的“联系我们”页面给我发送一些代码来看看。 – camickr 2010-12-14 22:07:32

+0

如果您正确使用它,它会起作用。但是,要获得实时输出,您需要将任何长时间运行的任务放到SwingWorker上。 – CaffeineToCode 2015-04-06 14:38:04