What we are missing
This is a continuation of the previous article. It is suggested to read it first before proceeding.The SystemOutLogger demo in the previous article has some major drawbacks. It only works for String output. For example :
System.out.println("Hello World !") // this works ! int number=12; System.out.println(number); // this doesn't work !
The reason is that we only overrode the method print(String) in SystemOutLogger.java, but not the method print(int).
To overcome this problem, we may choose to override print(int) as well. However, it is very clumsy since obviously we must also override print(float), print(double), print(long)...etc.
A better way is to override the "lower level" method. The write() method is a good candidate, because it is a good guess that all output should finally call the write() method.
We no longer need to override the print() and println() method once we override the write() method.
public void write(byte[] buf, int off, int len) { try { super.write(buf, off, len); // write to file consoleOut.write(buf, off, len); // write to console } catch (Exception ignore) { } }
It is not yet a complete console logger, because we only log System Output, but not System Error. It is simple to fix, just adding a single line to the constructor will do.
System.setErr(this); // redirect System Error
Demonstration
/****************************************************************************** * File : FullConsoleLogger.java * Author : http://java.macteki.com/ * Description : * A class to log the console output, it logs everything include : * 1. Normal String. e.g. System.out.println("hello"); * 2. Any object or primitive data type. e.g. System.out.println(i); * 3. All exception output. e.g. e.printStackTrace(); * Tested with : JDK 1.6 ******************************************************************************/ public class FullConsoleLogger extends java.io.PrintStream { private java.io.PrintStream consoleOut=null; // initialize a file output stream, also save the console output stream to a variable public FullConsoleLogger() throws Exception { super(new java.io.FileOutputStream("out.txt"),true); consoleOut = System.out; System.setOut(this); System.setErr(this); } public void write(byte[] buf, int off, int len) { try { super.write(buf, off, len); consoleOut.write(buf, off, len); } catch (Exception ignore) { } } // Testing program, which can be placed in another source file if you wish public static void main(String[] args) throws Exception { FullConsoleLogger logger = new FullConsoleLogger(); System.out.println("Logging output to out.txt"); System.out.print("Hello, "); // no line break, System.out.println("World !"); // "Hello World !" would be on the same line System.out.println(); // Add an empty line for (int i=0;i<10;i++) System.out.println(i); System.out.println("Thanks for visiting java.macteki.com"); throw new RuntimeException("Exception !!!"); } }
Advance Usage : SwingConsole
With a little effort, we may derive a class from FullConsoleLogger to display the console output to a Swing GUI component such as JTextArea. Since it is a subclass of FullConsoleLogger, both files must be in the same folder to compile and run.javac *.java java SwingConsole
/****************************************************************************** * File : SwingConsole.java * Author : http://java.macteki.com/ * Description : * 1. log the console output (out.txt) * 2. print the console output to a Swing component (JTextArea with scrollbar) * Tested with : JDK 1.6 ******************************************************************************/ public class SwingConsole extends FullConsoleLogger { private javax.swing.JPanel myPanel=null; private javax.swing.JTextArea myTextArea=null; private StringBuffer myBuffer=new StringBuffer(); // initialize a file output stream, also save the console output stream to a variable public SwingConsole() throws Exception { // initialize a JPanel for holding the output myTextArea = new javax.swing.JTextArea(); myTextArea.setBackground(java.awt.Color.CYAN); myTextArea.setForeground(java.awt.Color.BLUE); myTextArea.setEditable(false); // read only // wrap the text area inside a panel with scroll bar. javax.swing.JScrollPane scrollingPanel=new javax.swing.JScrollPane(myTextArea); scrollingPanel.setPreferredSize(new java.awt.Dimension(580,380)); // create a panel to hold the scrolling panel myPanel = new javax.swing.JPanel(); myPanel.add(scrollingPanel); myPanel.setPreferredSize(new java.awt.Dimension(600,400)); } public void write(byte[] buf, int off, int len) { try { super.write(buf, off, len); updateTextArea(buf, off, len); } catch (Exception ignore) { } } public void updateTextArea(byte[] buf, int off, int len) { String s=new String(buf,off,len); myBuffer.append(s); // write to buffer until linefeed found if (s.indexOf("\n")>=0) { // linefeed found, update TextArea myTextArea.append(myBuffer.toString()); // write to JTextArea myTextArea.setCaretPosition(myTextArea.getDocument().getLength()); // auto scroll keepLines(50); // keep 50 lines only myBuffer.setLength(0); // clear buffer } } // control how many lines to be kept in the JTextArea to avoid memory error public void keepLines(int maxLines) { try { javax.swing.text.Element root = myTextArea.getDocument().getDefaultRootElement(); if (root.getElementCount() > maxLines) { javax.swing.text.Element firstLine = root.getElement(0); myTextArea.getDocument().remove(0, firstLine.getEndOffset()); } } catch (Exception e) { e.printStackTrace(); } } // return a panel for holding the console output public javax.swing.JPanel getPanel() { return myPanel; } // Testing program, which can be placed in another source file if you wish public static void main(String[] args) throws Exception { SwingConsole console = new SwingConsole(); javax.swing.JFrame window=new javax.swing.JFrame(); window.setTitle("Macteki GUI console"); window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); window.add(console.getPanel()); window.pack(); window.setVisible(true); System.out.println("Logging output to out.txt"); System.out.print("Hello, "); // no line break, System.out.println("World !"); // "Hello World !" would be on the same line System.out.println(); // Add an empty line System.out.println("Thanks for visiting java.macteki.com"); for (int i=0;i<100;i++) { System.out.println("progress="+i+"%"); Thread.sleep(100); } System.out.println("Completed ! Check the file out.txt. "); System.out.println("You may also scroll up to check the text area"); System.out.println("If you wish to keep all output in the text area, "); System.out.println("set a bigger buffer size in the keepLine() method."); } }
Thanks for reading. Comments are welcome.
No comments:
Post a Comment