Search code examples
javaswingscheduled-tasksjtextareaswingutilities

JTextArea in other JFrame display realtime console output


I have a "ConsoleFrame" which should display my console output in real-time to a JTextArea.

I redirected the output streams:

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

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            updateTextArea(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));
}

and call the SwingUtilities.invokeAndWait method to append the new text, which works fine

private void updateTextArea(final String text) {
    try {
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                txt_console.append(text);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }
}

but it shows me in my new ConsoleFrame this error: java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread and I get that because of the EDT - but why does it work and how can I adapt my code to make it work properly?


Solution

    • invokeAndWait must be called out of EDT, otherwise caused a.m. exceptions,

    • carefully with invokeAndWait, because can freeze whole Swing GUI, locked by exceptions from RepaintManager (not in all cases only GUI is created, relayout, refreshed some of methods), then applications required restart,

    • for invokeAndWait is required to test if (EventQueue.isDispatchThread()) { / if (SwingUtilities.isEventDispatchThread()) { on true you can to setText("")/append("") without any side effects, output is done on EDT, but is about good practicies to wrap inside invokeLater

    • use SwingWorker, there are implemented methods process, publish, setProcess and done, all mentioned methods notified EDT by default,

    • SwingWorker is designated to run only once time, for repeatly (on some period) to use Executor for SwingWorker or Runnable#Thread as most simple, clear and without any side issues, effects