Search code examples
javaswingconsolesystemjtextarea

show data on a JTextArea instead of console


I want to have a JTextArea that can completely work instead of a console but I don't know how to do this!

Thank you


Solution

  • The solution to the problem is to redirect System.{in,out,err} to a JTextArea.


    • Starting with System.out it's pretty straight forward to to redirect it to your JTextArea component using System.setOut method. In the example below I've done this using pipes and SwingWorker but that is all fancy stuff to actually get the output simpler to the swing component.

    • Emulating System.in is simular, you need to redirect your keystrokes to the the System.in using System.setIn. Again, in the example below, I've used pipes to get a nicer interface. I also buffer the line (just like a "normal" console would do) till you hit enter. (Note that for example arrow keys will not work but it shouldn't be to much work to get it also to be handled/ignored.)


    The text in the screenshot below was produced by a number of calls to the "normal" System.out.print.. method and then waiting for input on System.in using a Scanner:

    screenshot

    public static JTextArea console(final InputStream out, final PrintWriter in) {
        final JTextArea area = new JTextArea();
    
        // handle "System.out"
        new SwingWorker<Void, String>() {
            @Override protected Void doInBackground() throws Exception {
                Scanner s = new Scanner(out);
                while (s.hasNextLine()) publish(s.nextLine() + "\n");
                return null;
            }
            @Override protected void process(List<String> chunks) {
                for (String line : chunks) area.append(line);
            }
        }.execute();
    
        // handle "System.in"
        area.addKeyListener(new KeyAdapter() {
            private StringBuffer line = new StringBuffer();
            @Override public void keyTyped(KeyEvent e) {
                char c = e.getKeyChar();
                if (c == KeyEvent.VK_ENTER) {
                    in.println(line);
                    line.setLength(0); 
                } else if (c == KeyEvent.VK_BACK_SPACE) { 
                    line.setLength(line.length() - 1); 
                } else if (!Character.isISOControl(c)) {
                    line.append(e.getKeyChar());
                }
            }
        });
    
        return area;
    }
    

    And the example main method:

    public static void main(String[] args) throws IOException {
    
        // 1. create the pipes
        PipedInputStream inPipe = new PipedInputStream();
        PipedInputStream outPipe = new PipedInputStream();
    
        // 2. set the System.in and System.out streams
        System.setIn(inPipe);
        System.setOut(new PrintStream(new PipedOutputStream(outPipe), true));
    
        PrintWriter inWriter = new PrintWriter(new PipedOutputStream(inPipe), true);
    
        // 3. create the gui 
        JFrame frame = new JFrame("\"Console\"");
        frame.add(console(outPipe, inWriter));
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    
        // 4. write some output (to JTextArea)
        System.out.println("Hello World!");
        System.out.println("Test");
        System.out.println("Test");
        System.out.println("Test");
    
        // 5. get some input (from JTextArea)
        Scanner s = new Scanner(System.in);
        System.out.printf("got from input: \"%s\"%n", s.nextLine());
    }