2013-12-13 95 views
5

我的问题是基于理论的问题,但它确实满足我的具体需求。在SwingWorker中处理错误

当你的SwingWorker抛出一个异常,你可以做什么,你可以预期和b)需要恢复和继续,但你想通知用户这个错误发生了?如何获取预期的例外情况并通知用户,而不违反“doInBackground()”中的“无Swing代码”规则?

考虑到这个问题,我已经制定了一个SSCCE,我想提出下面的问题。

SSCCE:

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.concurrent.ExecutionException; 
import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JProgressBar; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

public class Test { 

    public static void main(String args[]) { 
     final JFrame frame = new JFrame(); 
     JButton go = new JButton("Go."); 
     go.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       new Task(frame); 
      } 
     }); 
     frame.add(go); 
     frame.pack(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    static class Task extends SwingWorker<Void, Void> { 
     JFrame parent; 
     JDialog dialog; 
     public Task(JFrame parent) { 
      this.parent = parent; 
      dialog = new JDialog(parent); 
      JProgressBar jpb = new JProgressBar(); 
      jpb.setIndeterminate(true); 
      dialog.add(jpb); 
      dialog.setLocationRelativeTo(null); 
      dialog.setVisible(true); 
      execute(); 
     } 

     @Override 
     protected Void doInBackground() throws Exception { 
      for(int i = 0; i < 100000; i++) { 
       System.out.println(i); 
       try { 
        if(i == 68456) throw new IllegalStateException("Yikes! i = 68456."); 
       } catch (final IllegalStateException e) { 
        SwingUtilities.invokeAndWait(new Runnable() { 
         @Override 
         public void run() { 
          JOptionPane.showMessageDialog(parent, "Error: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); 
         } 
        }); 
       } 
      } 
      return null; 
     } 

     @Override 
     protected void done() { 
      if (!isCancelled()) { 
       try { 
        get(); 
       } catch (ExecutionException | InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      System.out.println("done"); 
      dialog.dispose(); 
     } 

    } 
} 

是否有效调用doInBackground()方法中SwingUtilities.invokeAndWait()我做了这方面的一些主题分析,结果是这样的:

enter image description here

一旦“转到”按钮被按下时,SwingWorker-pool-1-thread-1线程变为绿色。那么,当if条件满足时,就会抛出错误,并显示错误对话框,线程将变为黄色,并且AWT-EventQueue-0线程上确实有一个绿色的“blip”,表示EDT已被调用。我等了大约10秒,按下“确定”,并且SwingWorker线程再次变绿。

这样做有什么潜在的缺陷吗?有没有人有从SwingWorker实时通知用户计算错误的经验?

我会说实话,这种方法让我很沮丧。它似乎非正统,但我不能肯定地说这是否是一个坏主意。

+0

如果是处理异常,你可以不用在'doInBackground'中返回'Void'而是用'errorCode'' description'返回一些bean,或者当异常发生时调用'publish'来获得'process'调用并处理异常,或者你可以使用发生错误的'firePropertyChange' – nachokk

+0

确定我可以返回除'Void'之外的东西,但是它是我的SSCCE返回'Void'。我的真实应用可能需要返回中期结果。 – ryvantage

+0

SwingWorker没有被正确地使用doInBackground(工作者线程,而不是invokeAndWait的地方,只有在Initial Tread之后不是EDT时,如果EDT处于活动状态,则会导致异常),使用JOptionPane的发布(在EDT上完成), – mKorbel

回答

4

我看到没有问题,使用invokeAndWait()时,用户实际上需要批准。如果没有,如example所示,SwingWorker<Void, String>可以简单地调用publish(),其中交错的数据和错误消息。附加在done()中的适当消息将允许用户在必要时查看累计输出。