问题
I've been fooling around with Java and I was trying to make a program that starts to ping an address and printing out the "ms".
I have a JButton:
JButton start = new JButton("START");
start.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try {
doCommand();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
And the doCommand() method looks like this:
public static void doCommand() throws IOException{
String s = null;
ProcessBuilder pb = new ProcessBuilder(commands); //definiramo procesBuilder
Process proces = pb.start(); //zaženemo proces (vrne Process)
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proces.getInputStream())); //Branje outputa procesa
BufferedReader stdError = new BufferedReader(new InputStreamReader(proces.getErrorStream())); //Branje error outputa
while((s = stdInput.readLine()) != null){ //dokler output obstaja (ni error)
int dvop = s.indexOf(":") + 16;
if(s.startsWith("Reply")){
s=s.substring(dvop);
int pres = s.indexOf(" ");
s=s.substring(0,pres-2);
//System.out.println(s);
label.setText(s);
}
}
while((s = stdError.readLine()) != null){ //dokler error obstaja
System.out.println(s);
}
}
What happens is, everytime I press the button the program just freezes and nothing happens, I cant even close it the "normal" way... I guess I'm doing something wrong...
回答1:
An elaboration on StinePike's answer. Exactly to what he says, the actionPerformed() method will run on the main GUI event thread meaning the GUI may only respond when actionPerformed() returns. The code you have posted uses blocking I/O which may not complete in a swift manner.
Especially this line:
while((s = stdInput.readLine()) != null){
Which blocks on input from stdin. While this block is in effect the GUI becomes unresponsive as the method actionPerformed() has not returned yet.
Since you said the objective of this code is to return a response from a external application it may be that the external application has either: returned something on stderr or is blocking on another condition.
A possible solution is as follows:
The doCommand() method:
public static void doCommand() throws IOException{
String s = null;
ProcessBuilder pb = new ProcessBuilder(commands); //definiramo procesBuilder
Process proces = pb.start(); //zaženemo proces (vrne Process)
final BufferedReader stdInput = new BufferedReader(new InputStreamReader(proces.getInputStream())); //Branje outputa procesa
final BufferedReader stdError = new BufferedReader(new InputStreamReader(proces.getErrorStream())); //Branje error outputa
Thread readStdIn = new Thread(new Runnable(){
public void run(){
try{
while((s = stdInput.readLine()) != null){ //dokler output obstaja (ni error)
int dvop = s.indexOf(":") + 16;
if(s.startsWith("Reply")){
s=s.substring(dvop);
int pres = s.indexOf(" ");
s=s.substring(0,pres-2);
//System.out.println(s);
//Execute on the main AWT thread (I'm assuming 'label' is the name of one of your GUI components)
SwingUtilities.invokeLater(new Runnable(){
public void run(){
label.setText(s);
}
});
}
}
}catch(IOException ex){
//Handle This
}
}
});
Thread readStdErr = new Thread(new Runnable(){
public void run(){
try{
while((s = stdError.readLine()) != null){ //dokler error obstaja
System.out.println(s);
}
catch(IOException ex){
//Handle This Too
}
};
});
readStdIn.start();
readStdErr.start();
}
The above code will spawn two separate threads in which will read the contents of stdin and stderr and process them individually. Since the block I/O has been ported off the main GUI thread, the GUI should continue to be responsive even if the external application does something strange (such as freeze or deadlock).
Note: This will allow the button to be pressed even if the external application has no finished executing.
Edit: Added missing try-catch blocks for BufferedReader.readLine()
回答2:
actionPerformed method is executed on main thread. So if you perform heavy tasks in it then it will freeze the gui. Better use a different thread.
回答3:
You should use SwingWorker
that is for this task here you have a good tutorial and an example with File
Swing Worker example
来源:https://stackoverflow.com/questions/17241727/java-jbutton-actionperformed-freezing