简体   繁体   中英

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?

  • invokeAndWait must be called out of EDT, otherwise caused am 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

You can use SwingUtilities.invokeLater() from any thread, and for error stream it is likely best to use it even when you are already in EDT:

private void updateTextArea(final String text) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            txt_console.append(text);
        }
    });
}

That particular error you get comes from outside the EDT, and then invokeAndWait() may be called so you get the output to your console.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM