Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to send console progress information to gui

82 views
Skip to first unread message

mike

unread,
May 2, 2013, 2:49:34 PM5/2/13
to
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".

Daniel Pitts

unread,
May 2, 2013, 3:05:08 PM5/2/13
to
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.

mike

unread,
May 7, 2013, 7:50:58 AM5/7/13
to
Thanks for the idea. I appreciate it a lot.

//mike

Arne Vajhøj

unread,
May 18, 2013, 7:38:47 PM5/18/13
to
On 5/2/2013 2:49 PM, mike wrote:
> 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();
}
}
}


John B. Matthews

unread,
May 19, 2013, 12:34:42 AM5/19/13
to
In article <51981106$0$32109$1472...@news.sunsite.dk>,
Arne Vajhøj <ar...@vajhoej.dk> wrote:

> On 5/2/2013 2:49 PM, mike wrote:
> > 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.

[...]

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());

--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

Robert Klemme

unread,
May 21, 2013, 6:22:27 AM5/21/13
to
On Thursday, May 2, 2013 9:05:08 PM UTC+2, Daniel Pitts wrote:

> 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

Arne Vajhøj

unread,
Jun 1, 2013, 10:09:37 PM6/1/13
to
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


0 new messages