0

I have a program in which I call another separate program to do some works (lets call it sub-process), the sub-process takes some time to finish each task and shows the progress in a simple console.

The problem is, when I try to read that console using BufferedReader, my own program waits for the sub-process to finish before writing each line in a TextArea.

Here's the code I'm using to read each line:

    JTextArea report = new JTextArea(20,40);
    report.setText("");
    try
            {
                Process p = new ProcessBuilder(command).start();
                p.waitFor();
                BufferedReader reader=new BufferedReader(new  InputStreamReader(p.getInputStream()));
                String line = reader.readLine();
                while(line!=null) 
                { 
                report.append(line+"\n");
                line=reader.readLine(); 
                }
            }
            catch(IOException e1){ error.setText("Failed to run toxpack");}
            catch(InterruptedException e2) {error.setText("Failed to run command");}

I tried to look into threads, but It still wouldn't work.

How can I read each line and add them to my textArea without waiting for the whole sub-process to finish.

EDIT: added the rest of the code, but I'm not sure if it helps much. what I'm trying to say is, I want each line that sub-process outputs , to appear in my textArea. without waiting for it to finish.

Nogitsune
  • 27
  • 6

1 Answers1

0

You should create another thread which reads from the process, and updates the Swing component:

    final Process p = new ProcessBuilder("cat", "/etc/hosts").start();
    final BufferedReader br = new BufferedReader(new InputStreamReader(
            p.getInputStream()));

    final Runnable r = new Runnable() {
        @Override
        public void run() {
            try {
                try {
                    for (String line = br.readLine(); line != null; line = br
                            .readLine()) {
                        final String l = line;
                        System.out.println(l);
                        EventQueue.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                textArea.setText(textArea.getText() + "\n" + l);
                            }
                        });

                        Thread.sleep(50);
                    }
                } finally {
                    br.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    };

    final Thread t = new Thread(r);
    t.start();

Now the lines are read continuously in a reader thread, and the updates to Swing are posted into Swing's event queue using EventQueue.invokeLater, because the reading is not done in Swing's event dispatching thread (details: When to use invokeLater).

The sleep is only to slow it down a bit (to simulate data flowing in slowly).

Together with

public class TextAreaDemo {

public static void main(String[] args) {
    final JTextArea textArea = new JTextArea(60, 5);

    final JScrollPane sp = new JScrollPane(textArea,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS) {
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(600, 300);
        }

    };

    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(sp);
    frame.pack();
    frame.setVisible(true);

    // Add the reader snippet here
}

}

it will update the value in the text area.

Community
  • 1
  • 1
Beryllium
  • 12,808
  • 10
  • 56
  • 86
  • i tried this. still the same result. nothing will appear in textArea while the sub-process is working. – Nogitsune Aug 06 '13 at 12:43
  • I have posted the remaing part. Have you removed the `waitFor()` in your code? Have you tried to test it with a process which really produces something without input (like `cat /etc/hosts`)? – Beryllium Aug 06 '13 at 12:55
  • BTW does your program expect any input from the calling Java program? – Beryllium Aug 06 '13 at 13:09
  • nothing works. I'm beginning to think its the sub-processes fault somehow. thanks for help – Nogitsune Aug 06 '13 at 15:40
  • What happens, if you just type in the *command* for your sub process on the command line? Does it write something to `stdout`? What program is it anyway? – Beryllium Aug 06 '13 at 15:48
  • it's a program to uncompress and test archived files in a certain game. everything works fine when using cmd or directly from run, but in my GUI it just shows simple things like version and help in textArea. the progress bar and information while extracting or scanning file structure never shows up. – Nogitsune Aug 06 '13 at 16:48
  • In that case there is probably a problem with the arguments. How do you pass the arguments? – Beryllium Aug 06 '13 at 17:34
  • finally got it to work. your code was good. though I had a few other problems in between that effected the outcome. though its still not as quite line to line, it seem to read the input in periods and thus doesn't show everything. I take it I need more info on sub-processes output form to be perfect – Nogitsune Aug 06 '13 at 17:57
  • update: I thought it was working, but seems like with this code, the log in textArea start to appear when the sub-process is "close" to finishing.and won't show the whole progress log. still this is the closest I came to functional. so thanks for the code – Nogitsune Aug 06 '13 at 18:09