Chinaunix首页 | 论坛 | 博客
  • 博客访问: 822498
  • 博文数量: 92
  • 博客积分: 1498
  • 博客等级: 上尉
  • 技术积分: 993
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-18 18:31
文章分类

全部博文(92)

文章存档

2013年(2)

2012年(3)

2011年(3)

2010年(61)

2009年(23)

分类: LINUX

2009-11-21 19:03:10

最近在和几个java高手一起做几个javaIDE,不过是简略版本的,
我主要负责的是将编译程序的结果输出到我们的“控制台”
(其实是一个JTEXTPANE)上,其中遇到了一些麻烦,因为毕竟我的java很菜,
所以了,到处查资料,终于了解到了利用重定向System.out 和
System.err到JTextPane就可以了。
成功后心情很是爽啊,呵呵,现在将这个测试的代码贴上来和大家共享。





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

public class ConsolePane extends JScrollPane {
  
    private JTextPane textPane = new JTextPane();
  
    private static ConsolePane console = null;
  
    public static synchronized ConsolePane getInstance() {
        if (console == null) {
            console = new ConsolePane();
        }
        return console;
    }
  
    private ConsolePane() {
  
        setViewportView(textPane);
  
        // Set up System.out

        PrintStream mySystemOut = new MyPrintStream(System.out, Color.BLACK);
        System.setOut(mySystemOut);
  
        // Set up System.err

        PrintStream mySystemErr = new MyPrintStream(System.err, Color.RED);
        System.setErr(mySystemErr);
           
        textPane.setEditable(true);
        setPreferredSize(new Dimension(640, 120));
    }
  
    /**
     * Returns the number of lines in the document.
     */

    private final int getLineCount() {
        return textPane.getDocument().getDefaultRootElement().getElementCount();
    }
  
    /**
     * Returns the start offset of the specified line.
     * @param line The line
     * @return The start offset of the specified line, or -1 if the line is
     * invalid
     */

    private int getLineStartOffset(int line) {
        Element lineElement = textPane.getDocument().getDefaultRootElement()
                .getElement(line);
        if (lineElement == null)
            return -1;
        else
            return lineElement.getStartOffset();
    }
  
    /**
     * 清除超过行数时前面多出行的字符
     */

    private void replaceRange(String str, int start, int end) {
        if (end < start) {
            throw new IllegalArgumentException("end before start");
        }
        Document doc = textPane.getDocument();
        if (doc != null) {
            try {
                if (doc instanceof AbstractDocument) {
                    ((AbstractDocument) doc).replace(start, end - start, str,
                            null);
                } else {
                    doc.remove(start, end - start);
                    doc.insertString(start, str, null);
                }
            } catch (BadLocationException e) {
                throw new IllegalArgumentException(e.getMessage());
            }
        }
    }
  
    class MyPrintStream extends PrintStream {
  
        private Color foreground; //输出时所用字体颜色

           
        /**
         * 构造自己的 PrintStream
         * @param out 可传入 System.out 或 System.err, 实际不起作用
         * @param foreground 显示字体颜色
         */

        MyPrintStream(OutputStream out,Color foreground) {
            super(out,true); //使用自动刷新

            this.foreground = foreground;
        }
  
        /**
         * 在这里重截,所有的打印方法都要调用最底一层的方法
         */

        public void write(byte[] buf, int off, int len) {
            final String message = new String(buf, off, len);
  
            /** SWING非界面线程访问组件的方式 */
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    try {
  
                        StyledDocument doc = (StyledDocument) textPane
                                .getDocument();
  
                        // Create a style object and then set the style

                        // attributes

                        Style style = doc.addStyle("StyleName", null);
  
                        // Foreground color

                        StyleConstants.setForeground(style, foreground);
  
                        doc.insertString(doc.getLength(), message, style);
  
                    } catch (BadLocationException e) {
                        // e.printStackTrace();

                    }
  
                    // Make sure the last line is always visible

                    textPane.setCaretPosition(textPane.getDocument()
                            .getLength());
  
                    // Keep the text area down to a certain line count

                    int idealLine = 150;
                    int maxExcess = 50;
  
                    int excess = getLineCount() - idealLine;
                    if (excess >= maxExcess) {
                        replaceRange("", 0, getLineStartOffset(excess));
                    }
                }
            });
        }
    }
}


把 System.out 和 System.err 重定向到 JTextArea 的做法在网上能找到不少,由于 JTextArea 不能用不同的字体分别显示内容。但我还是希望能象 Eclipse 控制台那样,标准输出为黑色,错误信息为红色,于是选择了 JTextPane 作为输出目的地。线程之间通信息用到了 PipedInputStream 、PipedOutputStream 和 SwingUtilities.invokeLater(new Runnable())。

自定义了一个 JScrollPane,类名为 ConsolePane,写成的单例类;使用时只需要在你的面板上加上 ConsolePane组件,例如:getContentPane().add(ConsolePane.getInstance(), BorderLayout.CENTER);

阅读(1453) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~