Java JButton actionPerformed freezing

孤人 提交于 2020-01-05 10:11:34

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!