2011-06-29 64 views
22

我在通过Swing Worker类的应用程序中使用线程。它工作正常,但我有一个不好的感觉,显示try-catch块中的错误消息对话框。它可能会阻止应用程序?这是它看起来现在:Swing Worker中优雅的异常处理

SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { 

    // Executed in background thread 
    public Void doInBackground() { 
     try { 
      DoFancyStuff(); 
     } catch (Exception e) { 

      e.printStackTrace(); 

      String msg = String.format("Unexpected problem: %s", e 
        .toString()); 

      //TODO: executed in background thread and should be executed in EDT? 
      JOptionPane.showMessageDialog(Utils.getActiveFrame(), 
        msg, "Error", JOptionPane.ERROR_MESSAGE, 
        errorIcon); 

     }//END: try-catch 

     return null; 
    } 

    // Executed in event dispatch thread 
    public void done() { 
     System.out.println("Done"); 
    } 
}; 

它可以使用的Swing工作器框架安全的方式来完成?在这里重写publish()方法是一个好主意吗?

编辑:

难道这样的:

} catch (final Exception e) { 

    SwingUtilities.invokeLater(new Runnable() { 

     public void run() { 

      e.printStackTrace(); 

      String msg = String.format(
        "Unexpected problem: %s", e.toString()); 

      JOptionPane.showMessageDialog(Utils 
        .getActiveFrame(), msg, "Error", 
        JOptionPane.ERROR_MESSAGE, errorIcon); 

     } 
    }); 

} 

调用get中完成的方法将导致两个的try-catch块,如计算部分抛出异常,所以我认为这是清洁剂。

回答

13

一种选择是使用SwingUtilities.invokeLater(...)张贴在EDT

SwingUtilities.invokeLater(new Runnable(){ 
    @Override 
    public void run(){ 
     JOptionPane.showMessageDialog(
      Utils.getActiveFrame(), 
      msg, 
      "Error", 
      JOptionPane.ERROR_MESSAGE, 
      errorIcon); 
    } 
}); 

的行动,并为你指出的,SwingWorker能够报告中间结果的,但你需要重写process(...),这就是所谓时你调用publish(...)

无论如何,如果发生异常,为什么不设置一个标志,如果设置了该标志,则显示done()中的对话框,因为它在EDT中安全执行?

+4

在done()方法中处理它正是我过去如何处理这种情况。 invokeLater也是一个很好的解决方案。 – jzd

+0

是和不是太,但回答OP的问题+1 – mKorbel

+1

1)我永远不会允许运行任何代码,可以抛出异常内部SwingWorker 2)PropertyChangeListener将捕获任何从SwingWorker exeption 3)所有看起来像建设大麻烦去这样:-) – mKorbel

1

您是对的,您违反了Swing的基本规则,即除了事件派发线程之外,不会修改GUI。

如果是我,我会抛出一个GUI监听的事件来显示错误消息。或者,您可以将SwingWorker的调用封装在try catch中并在那里显示对话。

51

正确的方式做到这一点如下:

SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { 
    // Executed in background thread 
    protected Void doInBackground() throws Exception { 
     DoFancyStuff(); 
     return null; 
    } 

    // Executed in EDT 
    protected void done() { 
     try { 
      System.out.println("Done"); 
      get(); 
     } catch (ExecutionException e) { 
      e.getCause().printStackTrace(); 
      String msg = String.format("Unexpected problem: %s", 
          e.getCause().toString()); 
      JOptionPane.showMessageDialog(Utils.getActiveFrame(), 
       msg, "Error", JOptionPane.ERROR_MESSAGE, errorIcon); 
     } catch (InterruptedException e) { 
      // Process e here 
     } 
    } 
} 

你不应该试图捕获异常在后台线程,而是让他们通过对SwingWorker类本身,那么您可以在让他们通过调用get()done()方法,通常返回doInBackground()Void在您的情况)的结果。如果在后台线程中抛出异常,则get()将抛出它,并包装在ExecutionException中。

另请注意,过滤SwingWorker方法是protected,你不需要使它们成为public

+0

这是关于try-catch - finally嵌套类内部创建的SwingWorkers方法/ funcionality(ies):-) +1 – mKorbel

+0

这个工作方式也一样,就我测试而言,但在我的情况下增加了很多代码。计算部分抛出异常,所以我不得不添加两块try-catch。但要记住。 – fbielejec

+2

然后在这种情况下,我们可能会想知道为什么你使用'SwingWorker'并且不使用自己的线程作为后台工作,因为你没有使用任何相关的'SwingWorker'功能。另请注意,你的代码不会处理后台线程的中断。 – jfpoilpret