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;
}
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
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