简体   繁体   English

Java JButton操作执行冻结

[英]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". 我一直在鬼混Java,并且试图制作一个程序来开始ping地址并打印出“ ms”。

I have a JButton: 我有一个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: 而doCommand()方法如下所示:

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. 详细介绍StinePike的答案。 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. 确切地说,actionPerformed()方法将在主GUI事件线程上运行,这意味着GUI仅在actionPerformed()返回时才响应。 The code you have posted uses blocking I/O which may not complete in a swift manner. 您发布的代码使用的阻塞I / O可能无法迅速完成。

Especially this line: 特别是这一行:

while((s = stdInput.readLine()) != null){

Which blocks on input from stdin. 哪个阻止来自stdin的输入。 While this block is in effect the GUI becomes unresponsive as the method actionPerformed() has not returned yet. 当此块生效时,由于方法actionPerformed()尚未返回,因此GUI变得无响应。

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. 既然您说的是这段代码的目的是从外部应用程序返回响应,则可能是外部应用程序已执行以下操作:在stderr上返回了某些内容,或者在另一情况下正在阻塞。

A possible solution is as follows: 可能的解决方案如下:

The doCommand() method: doCommand()方法:

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. 上面的代码将产生两个单独的线程,其中将读取stdin和stderr的内容并分别进行处理。 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). 由于块I / O已从主GUI线程中移出,因此即使外部应用程序做了一些奇怪的事情(例如冻结或死锁),GUI也应继续响应。

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() 编辑:为BufferedReader.readLine()添加了丢失的try-catch块

actionPerformed method is executed on main thread. actionPerformed方法在主线程上执行。 So if you perform heavy tasks in it then it will freeze the gui. 因此,如果您在其中执行繁重的任务,它将冻结gui。 Better use a different thread. 最好使用其他线程。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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