2013-06-21 99 views
1

我一直在與Java搞鬼,我試圖做一個程序,開始ping一個地址,並打印出「ms」。Java JButton actionPerformed freeze

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

} 

會發生什麼情況是,每次我按下按鈕的程序只是凍結,並沒有任何反應,我甚至不能關閉它的「正常」的方式... 我想我做錯了什麼...

+0

一個例子你應該使用'SwingWorker'來處理繁重的事情,那麼擁有標籤的類就是swingWorker的觀察者,swingWorker會通知作品結束,並且你在'EDT'中更新你的標籤。 – nachokk

回答

3

對StinePike答案的闡述。對於他所說的,actionPerformed()方法將在主GUI事件線程上運行,這意味着GUI可能僅在actionPerformed()返回時纔會響應。您發佈的代碼使用阻止I/O,可能無法快速完成。

特別這一行:

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

上從stdin輸入哪些塊。當該塊生效時,由於actionPerformed()方法尚未返回,因此GUI變得無響應。

既然你說過這段代碼的目標是從外部應用程序返回一個響應,那麼外部應用程序可能會有:在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(); 
} 

上面的代碼將產生兩個獨立的線程,其中將讀取標準輸入和錯誤的內容,並單獨處理它們。由於塊I/O已從主GUI線程移出,因此即使外部應用程序出現異常(例如凍結或死鎖),GUI也應該繼續保持響應。

注意:即使外部應用程序沒有完成執行,也可以按下該按鈕。

編輯:新增失蹤的try-catch塊BufferedReader.readLine()

2

actionPerformed方法在主線程上執行。所以如果你在其中執行繁重的任務,那麼它會凍結gui。更好地使用不同的線程。