Progress bar in Swing (Java) for command tools
I have several C/C++ command line tools that I'm wrapping with Java.Swing as GUI. The command line tools can take minutes to hours. Progress bar seems like a good idea to keep users sane. I'm also thinking it might be nice to wrap a GUI for the progress bar, instead of just using system out. But how?
I'm thinking the command line tools can write percents to stderr and I can somehow read it in java. Not exactly sure what the mechanics for this would be. I'm also not clear on asynchronous display (learned a bit about invokeLater() ). New to Java, and would appreciate general suggestions as well. Thanks.
--- update ---
Thanks everyone for your suggestions. Here's the resulting code.
private void redirectSystemStreams() {
OutputStream out_stderr = new OutputStream() {
@Override
public void write(final int b) throws IOException {
update(String.valueOf((char) b));
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
update(new String(b, off, len));
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
};
System.setErr(new PrintStream(out_stderr, true));
}
private void update(final String inputText) {
int value = 20; //parse inputText; make sure your executable calls fflush(stderr) after each fprintf().
jProgressBar.setValue(value);
/* Also one can redirect to a textpane
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//update jTextPane with inputT开发者_StackOverflowext
}
});
*/
}
That's seems very fragile, better would be to communicate via sockets in a well established protocol or with some sort of RCP ( perhaps Google's protobuf ) or even webservices.
If you still insists you can launch a process in Java with ProcessBuilder that will give you a Process reference of which you can get the InputStream to read the standard output, but again, that seems very fragile to me.
I hope this helps.
For the progress bar part of your problem you can do something like the following. Note that this is just an example to illustrate the point.
Basically, a thread is created to do the work. Presumably this Runner thread will be interacting with your C/C++ code to get its progress. It then calls update on the Progress Bars Dialog class.
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
public class Main {
private int value;
private Progress pbar;
public static void main(String args[]) {
new Main();
}
public Main() {
pbar = new Progress();
Thread t = new Thread(new Runner());
t.start();
}
class Progress extends JDialog {
JProgressBar pb;
JLabel label;
public Progress() {
super((JFrame) null, "Task In Progress");
pb = new JProgressBar(0, 100);
pb.setPreferredSize(new Dimension(175, 20));
pb.setString("Working");
pb.setStringPainted(true);
pb.setValue(0);
label = new JLabel("Progress: ");
JPanel panel = new JPanel();
panel.add(label);
panel.add(pb);
add(panel, BorderLayout.CENTER);
pack();
setVisible(true);
}
public void update(){
pb.setValue(value);
if(value >= 100){
this.setVisible(false);
this.dispose();
}
}
}
class Runner implements Runnable {
public void run() {
for (int i = 0; i <= 100; i++) {
value++;
pbar.update();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
}
}
}
// Create a window
JFrame frame = new JFrame("Progress");
// Creates a progress bar and add it to the window
JProgressBar prog = new JProgressBar();
frame.add(prog);
// Run C/C++ application
try {
Process p = Runtime.getRuntime().exec(new String[]{"filename","arg1","arg2","..."});
// Get InputStream
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
// Update the progress when recieving output from C/C++
new java.util.Timer().schedule(new TimerTask(){
public void run(){
String str = "";
while ((str=br.readLine()!=null) {
prog.setValue(new Integer(str)); // Set Value of Progress Bar
prog.setString(str+"%"); // Set Value to display (in text) on Progress Bar
}
}
},0,100); // Check every 100 milliseconds
// Fit the window to its contents and display it
frame.pack();
frame.setVisible(true);
} catch (Exception e) {
System.out.println("Failed To Launch Program or Failed To Get Input Stream");
}
精彩评论