0

When creating a new dialog containing a text area and then running code that outputs to the text area, the text area is not showing up until the code execution finishes. I would like the text area to refresh while the code is executing. Here is some sample code that demonstrates the problem.

package textareatester;

import java.io.PrintStream;
import javax.swing.JOptionPane;


public class NewJFrame extends javax.swing.JFrame
{

    /**
     * Creates new form NewJFrame
     */
    public NewJFrame()
    {
        initComponents();
    }


    @SuppressWarnings("unchecked")
  private void initComponents()
  {

    jButton1 = new javax.swing.JButton();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    jButton1.setText("Test Me");
    jButton1.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        jButton1ActionPerformed(evt);
      }
    });

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
        .addContainerGap(175, Short.MAX_VALUE)
        .addComponent(jButton1)
        .addGap(154, 154, 154))
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addGap(113, 113, 113)
        .addComponent(jButton1)
        .addContainerGap(164, Short.MAX_VALUE))
    );

    pack();
  }                    

  private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)                                         
  {                                             

        NewJDialog dialog = new NewJDialog(this, "Output", false );
        dialog.setVisible(true);
        PrintStream ps = System.out;
        System.setOut(new PrintStream(new StreamCapturer("STDOUT", dialog, ps)));
        OutputMaker oMaker = new OutputMaker(); 
        oMaker.makeOutput();
        JOptionPane.showMessageDialog(this,"OUtput ran successfully!", "Success!", JOptionPane.INFORMATION_MESSAGE);
  }                                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[])
    {

        try
        {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
            {
                if ("Nimbus".equals(info.getName()))
                {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex)
        {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex)
        {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex)
        {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex)
        {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }


        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                new NewJFrame().setVisible(true);
            }
        });
    }


  private javax.swing.JButton jButton1;

}


package textareatester;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;


public class StreamCapturer extends OutputStream
{

    private StringBuilder buffer;
    private String prefix;
    private NewJDialog consumer;
    private PrintStream old;

    public StreamCapturer(String prefix, NewJDialog consumer, PrintStream old)
    {
        this.prefix = prefix;
        buffer = new StringBuilder(128);
        buffer.append("[").append(prefix).append("] ");
        this.old = old;
        this.consumer = consumer;
    }

    @Override
    public void write(int b) throws IOException
    {
        char c = (char) b;
        String value = Character.toString(c);
        buffer.append(value);
        if (value.equals("\n"))
        {
            consumer.appendText(buffer.toString());
            buffer.delete(0, buffer.length());
            buffer.append("[").append(prefix).append("] ");
        }
        old.print(c);
    }

}

package textareatester;

import java.util.logging.Level;
import java.util.logging.Logger;


public class OutputMaker
{
    public void makeOutput()
    {
        try
        {
            System.out.println("Output for line 1.");
            Thread.sleep(2000);
            System.out.println("Output for line 2.");
            Thread.sleep(2000);
            System.out.println("Output for line 3.");
            Thread.sleep(2000);
            System.out.println("Output for line 4.");
            Thread.sleep(2000);
            System.out.println("Output for line 5.");
        } catch (InterruptedException ex)
        {
            Logger.getLogger(OutputMaker.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

package textareatester;

import java.awt.EventQueue;


public class NewJDialog extends javax.swing.JDialog
{

    /**
     * Creates new form NewJDialog
     */
    public NewJDialog(java.awt.Frame parent, boolean modal)
    {
        this(parent, "", modal);
    }
    public NewJDialog(java.awt.Frame parent, String title, boolean modal)
    {
        super(parent, title, modal);
        initComponents();
    }

    @SuppressWarnings("unchecked")

  private void initComponents()
  {

    jScrollPane2 = new javax.swing.JScrollPane();
    jTextArea1 = new javax.swing.JTextArea();

    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

    jTextArea1.setColumns(20);
    jTextArea1.setRows(5);
    jScrollPane2.setViewportView(jTextArea1);

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 410, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
    );

    pack();
  }               

    public void appendText(final String text)
    {
        if (EventQueue.isDispatchThread())
        {
            jTextArea1.append(text);
            jTextArea1.setCaretPosition(jTextArea1.getText().length());
        } else
        {

            EventQueue.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    appendText(text);
                }
            });

        }
    }


  private javax.swing.JScrollPane jScrollPane2;
  private javax.swing.JTextArea jTextArea1;

}
kymnyth
  • 65
  • 1
  • 7
  • See [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) for the reason why you're having problems and [Worker Threads and SwingWorker](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html) for a possible solution – MadProgrammer Mar 17 '16 at 21:02
  • I appreciate your input. However, I have read through the tutorial trail and I am not understanding how that applies in this situation and how to adjust the code to fix it. Any further comment would be greatly appreciated. – kymnyth Mar 17 '16 at 21:29
  • Never use `Thread.sleep` within the context of the EDT – MadProgrammer Mar 17 '16 at 21:41
  • I used sleep to "slow down" the execution of the OutputMaker to represent processing taking place. – kymnyth Mar 17 '16 at 22:52
  • That's right, but until the jButton1ActionPerformed method returns, the ui won't be updated, because you're blocking the EDT, so it can't update the ui until after the metics returns – MadProgrammer Mar 17 '16 at 22:59
  • Swing is single threaded, all it's event dispatching is done from within the context of the EDT, meaning your jButton1ActionPerformed method is called in the EDT. So until it exists, all the repaint and other events used to update the ui won't be processed – MadProgrammer Mar 17 '16 at 23:04

1 Answers1

2

From what I can tell, you code is based on my previous answer

The problem is, you're using Thread.sleep from within the context of the Event Dispatching Thread, which is prevent it from processing any new events (including repaint events) until after the jButton1ActionPerformed returns.

Instead, you need to be using a separate thread, like SwingWorker or just a plain old thread (seen as the append method synchronises updates to the UI by itself), for example

Clickity Clack

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestRedirect {

    public static void main(String[] args) {
        new TestRedirect();
    }

    public TestRedirect() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                CapturePane capturePane = new CapturePane();
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(capturePane);
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                PrintStream ps = System.out;
                System.setOut(new PrintStream(new StreamCapturer("STDOUT", capturePane, ps)));
            }
        });
    }

    public class CapturePane extends JPanel implements Consumer {

        private JTextArea output;

        public CapturePane() {
            setLayout(new BorderLayout());
            output = new JTextArea();
            add(new JScrollPane(output));

            JButton test = new JButton("Test");
            test.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    SwingWorker worker = new SwingWorker() {
                        @Override
                        protected Object doInBackground() throws Exception {
                            System.out.println("Hello world");
                            Thread.sleep(1000);
                            System.out.println("I'm calling you from another thread");
                            Thread.sleep(1000);
                            System.out.println("But you can still see the updates as they occur");
                            return null;
                        }

                        @Override
                        protected void done() {
                            test.setEnabled(true);  
                        }

                    };
                    test.setEnabled(false);
                    worker.execute();
                }
            });
            add(test, BorderLayout.SOUTH);
        }

        @Override
        public void appendText(final String text) {
            if (EventQueue.isDispatchThread()) {
                output.append(text);
                output.setCaretPosition(output.getText().length());
            } else {

                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        appendText(text);
                    }
                });

            }
        }
    }

    public interface Consumer {

        public void appendText(String text);
    }

    public class StreamCapturer extends OutputStream {

        private StringBuilder buffer;
        private String prefix;
        private Consumer consumer;
        private PrintStream old;

        public StreamCapturer(String prefix, Consumer consumer, PrintStream old) {
            this.prefix = prefix;
            buffer = new StringBuilder(128);
            buffer.append("[").append(prefix).append("] ");
            this.old = old;
            this.consumer = consumer;
        }

        @Override
        public void write(int b) throws IOException {
            char c = (char) b;
            String value = Character.toString(c);
            buffer.append(value);
            if (value.equals("\n")) {
                consumer.appendText(buffer.toString());
                buffer.delete(0, buffer.length());
                buffer.append("[").append(prefix).append("] ");
            }
            old.print(c);
        }
    }
}

See Concurrency in Swing and Worker Threads and SwingWorker for more details

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366