简体   繁体   中英

Java JButton actionPerformed freezing

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...

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.

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.

您应该使用SwingWorker来完成此任务,这里您有一个不错的教程和File Swing Worker示例的示例

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM