1

我一直在玩 Java,我试图制作一个开始 ping 地址并打印出“ms”的程序。

我有一个 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();
            }

        }
    });

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);
    }

}

发生的事情是,每次我按下按钮时程序都会冻结并且什么也没有发生,我什至无法以“正常”的方式关闭它......我想我做错了什么......

4

3 回答 3

3

对 StinePike 答案的详细说明。正如他所说,actionPerformed() 方法将在主 GUI 事件线程上运行,这意味着 GUI 可能仅在 actionPerformed() 返回时响应。您发布的代码使用了可能无法快速完成的阻塞 I/O。

特别是这一行:

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

哪些阻塞来自标准输入的输入。当此块生效时,GUI 变得无响应,因为方法 actionPerformed() 尚未返回。

由于您说此代码的目标是从外部应用程序返回响应,因此外部应用程序可能具有:在 stderr 上返回某些内容或在其他条件下阻塞。

一个可能的解决方案如下:

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();
}

上面的代码将生成两个单独的线程,在其中读取 stdin 和 stderr 的内容并单独处理它们。由于块 I/O 已从主 GUI 线程中移植,因此即使外部应用程序做了一些奇怪的事情(例如冻结或死锁),GUI 也应该继续响应。

注意:这将允许按下按钮,即使外部应用程序没有完成执行。

编辑:为 BufferedReader.readLine() 添加了缺失的 try-catch 块

于 2013-06-21T19:20:39.950 回答
2

actionPerformed 方法在主线程上执行。因此,如果您在其中执行繁重的任务,那么它将冻结 gui。最好使用不同的线程。

于 2013-06-21T18:12:33.707 回答
2

你应该使用SwingWorker它来完成这个任务在这里你有一个很好的教程和一个带有File Swing Worker 示例的示例

于 2013-06-21T19:48:34.040 回答