Swing Worker append text area not executing until after all other threads finished

370 Views Asked by At

I want a swing text area to be updated during my program running. My program does a lot of complex file processing.

In my program I have a text area that I can update using writeText("text") for example (method shown below). In the writeText() method I do this with a simple textArea.append() with a swing worker but it doesn't update the text until after all the processing happens in my main class. How do I make this work properly by actually updating the text area in real time like how System.out.println() can send text to the console at any time.

    public static void writeText(String text) {
            System.out.println("SWING WORKER");
            worker = new SwingWorker<Void, String>() {
                @Override
                protected Void doInBackground() throws Exception {
                    publish(" " + text + "\n");
                    return null;
                }
                
                @Override
                protected void process(List<String> chunks) {
                    textArea.append(chunks.get(chunks.size() - 1));
                    frame.repaint();
                }
                
                @Override
                protected void done() {
                    //textArea.append(" test done\n");
                }
                
            };
            worker.execute();
        }  

I have tried threading and now using swing worker but both attempts only updated the text after the main complex method ran (copying and renaming and subimaging out files that kinda stuff, basically I just want the text area to be updated with an append() so the user knows whats happening while the program runs)

1

There are 1 best solutions below

0
MadProgrammer On

It sounds like something else is blocking the main thread, but it's impossible to know what without more context.

It's important that what ever long running work you are doing is done within the doBackground method, so as to prevent the event dispatching thread from been blocked (and unable to process new events, including paint request).

The following example simply reads a text file, line by line, and with a random delay, publishes the line, so it can be added to the JTextArea

Scrolly

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingWorker;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTextArea textArea;

        public TestPane() {
            setLayout(new BorderLayout());
            textArea = new JTextArea(40, 40);
            add(new JScrollPane(textArea));

            SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
                @Override
                protected Void doInBackground() throws Exception {
                    try (BufferedReader br = new BufferedReader(new InputStreamReader(TestPane.this.getClass().getResourceAsStream("Script.txt")))) {
                        String text = null;
                        Random rnd = new Random();
                        while ((text = br.readLine()) != null) {
                            publish(text);
                            Thread.sleep(rnd.nextInt(500));
                        }
                    } catch (IOException exp) {
                        exp.printStackTrace();
                        publish("Failed to load script file: " + exp.getMessage());
                    }
                    return null;
                }

                @Override
                protected void process(List<String> chunks) {
                    for (String text : chunks) {
                        textArea.append(text);
                        textArea.append("\n");
                    }
                }
            };

            getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "start");
            getActionMap().put("start", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    worker.execute();
                }
            });
        }

    }
}

You should also be sure to read through Worker Threads and SwingWorker