How to send console progress information to gui

M

mike

Hi,

I am using java to send a commdline arg 'mklabel –config hello.o REL3'.
The output that I get is a new line for each element a put the label on.
In my application I want to show the user the progress of the command.
Can I create an event that contains the information for each line and send it to a listener? Or is there a better way?


br,

//mike

Output from console:
mklabel –config hello.o REL3
Created label "REL3" on "/usr/hw/" version "/main/1".
Created label "REL3" on "/usr/hw/src" version "/main/2".
Created label "REL3" on "/usr/hw/src/hello.c" version "/main/3".
Created label "REL3" on "/usr/hw/src/hello.h" version "/main/1".
 
D

Daniel Pitts

Hi,

I am using java to send a commdline arg 'mklabel –config hello.o REL3'.
The output that I get is a new line for each element a put the label on.
In my application I want to show the user the progress of the command.
Can I create an event that contains the information for each line and send it to a listener? Or is there a better way?


br,

//mike

Output from console:
mklabel –config hello.o REL3
Created label "REL3" on "/usr/hw/" version "/main/1".
Created label "REL3" on "/usr/hw/src" version "/main/2".
Created label "REL3" on "/usr/hw/src/hello.c" version "/main/3".
Created label "REL3" on "/usr/hw/src/hello.h" version "/main/1".

You would start a thread to read the data out of the InputStream (which
you need to do anyway to make a Process work as expected). The thread
reading the data could send an event anywhere. If you are updating a UI
thread, I suggest the following approach:

ProgressTrackerThread.run() will read from InputStream, and when newline
happens, call "progressUpdated" on a list of Listeners.

Create an abstract EventQueueProgressListener implementation.
progressUpdated in this impl will be final, and will pass a Runnable to
the EventQueue, which then calls a different abstract method
(handleProgressUpdated maybe?). That way, you're thread-safe on the EDT
for UI updates.
 
M

mike

You would start a thread to read the data out of the InputStream (which

you need to do anyway to make a Process work as expected). The thread

reading the data could send an event anywhere. If you are updating a UI

thread, I suggest the following approach:



ProgressTrackerThread.run() will read from InputStream, and when newline

happens, call "progressUpdated" on a list of Listeners.



Create an abstract EventQueueProgressListener implementation.

progressUpdated in this impl will be final, and will pass a Runnable to

the EventQueue, which then calls a different abstract method

(handleProgressUpdated maybe?). That way, you're thread-safe on the EDT

for UI updates.


Thanks for the idea. I appreciate it a lot.

//mike
 
A

Arne Vajhøj

I am using java to send a commdline arg 'mklabel –config hello.o REL3'.
The output that I get is a new line for each element a put the label on.
In my application I want to show the user the progress of the command.
Can I create an event that contains the information for each line and send it to a listener? Or is there a better way?

Assuming you use Swing for GUI then see the code below for inspiration.

Arne

====

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class CommandOutputDisplay extends JFrame {
private static final long serialVersionUID = 1L;
private JTextArea out;
private JTextArea err;
private JTextField cmd;
private JButton exe;
public CommandOutputDisplay() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
JPanel outerr = new JPanel();
outerr.setLayout(new GridLayout(1, 2));
JPanel outwrap = new JPanel();
outwrap.setLayout(new BorderLayout());
outwrap.add(new JLabel("Output"), BorderLayout.NORTH);
out = new JTextArea(20, 80);
outwrap.add(new JScrollPane(out), BorderLayout.CENTER);
outerr.add(outwrap);
JPanel errwrap = new JPanel();
errwrap.setLayout(new BorderLayout());
errwrap.add(new JLabel("Error"), BorderLayout.NORTH);
err = new JTextArea(20, 80);
errwrap.add(new JScrollPane(err), BorderLayout.CENTER);
outerr.add(errwrap);
getContentPane().add(outerr, BorderLayout.CENTER);
JPanel cmdexe = new JPanel();
cmdexe.setLayout(new BorderLayout());
cmdexe.add(new JLabel("Command:"), BorderLayout.WEST);
cmd = new JTextField("", 80);
cmdexe.add(cmd, BorderLayout.CENTER);
exe = new JButton("Execute");
exe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
execute();
}
});
cmdexe.add(exe, BorderLayout.EAST);
getContentPane().add(cmdexe, BorderLayout.SOUTH);
pack();
}
private void execute() {
try {
Process p = Runtime.getRuntime().exec(cmd.getText());
(new GUIReader(p.getInputStream(), out)).start();
(new GUIReader(p.getErrorStream(), err)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new CommandOutputDisplay();
f.setVisible(true);
}
});
}
}

class GUIReader extends Thread {
private BufferedReader br;
private JTextArea ta;
public GUIReader(InputStream is, JTextArea ta) {
this.br = new BufferedReader(new InputStreamReader(is));
this.ta = ta;
}
public void run() {
String line;
try {
while((line = br.readLine()) != null) {
final String line2 = line;
EventQueue.invokeLater(new Runnable() {
public void run() {
ta.append(line2 + "\r\n");
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
 
J

John B. Matthews

Arne Vajhøj said:
Assuming you use Swing for GUI then see the code below for
inspiration.

[...]

If I may offer a few enhancements to your excellent sscce, it may be
convenient to set the default button and focus the text field:

getRootPane().setDefaultButton(exe);
cmd.requestFocusInWindow();

ProcessBuilder allows one to combine the streams and eliminate a pane:

ProcessBuilder pb = new ProcessBuilder(cmd.getText().split(" "));
pb.redirectErrorStream();
Process p = pb.start();
(new GUIReader(p.getInputStream(), out)).start();

It may be useful to append diagnostic output in the exception handler:

StringBuilder sb = new StringBuilder(e.getMessage());
sb.append(e.getMessage());
sb.append("\n");
for (StackTraceElement ste : e.getStackTrace()) {
sb.append(ste.toString());
sb.append("\n");
}
out.append(sb.toString());
 
R

Robert Klemme

You would start a thread to read the data out of the InputStream (which
you need to do anyway to make a Process work as expected). The thread
reading the data could send an event anywhere. If you are updating a UI
thread, I suggest the following approach:

ProgressTrackerThread.run() will read from InputStream, and when newline
happens, call "progressUpdated" on a list of Listeners.

Create an abstract EventQueueProgressListener implementation.
progressUpdated in this impl will be final, and will pass a Runnable to
the EventQueue, which then calls a different abstract method
(handleProgressUpdated maybe?). That way, you're thread-safe on the EDT
for UI updates.

There is SwingWorker for such things.
http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html

You still need an additional thread since there are two streams to read from (alternatively use a Selector from NIO).

Kind regards

robert
 
A

Arne Vajhøj

Arne Vajhøj said:
Assuming you use Swing for GUI then see the code below for
inspiration.

[...]

If I may offer a few enhancements to your excellent sscce, it may be
convenient to set the default button and focus the text field:

getRootPane().setDefaultButton(exe);
cmd.requestFocusInWindow();

ProcessBuilder allows one to combine the streams and eliminate a pane:

ProcessBuilder pb = new ProcessBuilder(cmd.getText().split(" "));
pb.redirectErrorStream();
Process p = pb.start();
(new GUIReader(p.getInputStream(), out)).start();

It may be useful to append diagnostic output in the exception handler:

StringBuilder sb = new StringBuilder(e.getMessage());
sb.append(e.getMessage());
sb.append("\n");
for (StackTraceElement ste : e.getStackTrace()) {
sb.append(ste.toString());
sb.append("\n");
}
out.append(sb.toString());

I would like to know whether something came from out or err.

But then I am not a typical GUI user, so you are probably right.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top