我通过Swing Worker类在应用程序中使用线程。它工作正常,但我对在try-catch块中显示错误消息对话框感觉不好。它可能会阻止应用程序吗?这就是它现在的样子:
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 Worker框架以安全的方式完成吗?覆盖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 in done方法会导致两个try-catch块,因为计算部分会抛出异常,所以我认为最终会更清晰。
答案 0 :(得分:56)
正确的方法如下:
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本身,然后你可以通过调用done()
来获取get()
方法,这通常会返回doInBackground()
(Void
的结果)。如果在后台线程中抛出异常,则get()
将抛出异常,包含在ExecutionException
内。
另请注意,隐藏的SwingWorker
方法为protected
,您无需进行public
。
答案 1 :(得分: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
中安全执行了?
答案 2 :(得分:1)
你是对的,你违反了Swing的基本规则,除了事件派遣线程之外,它不会修改任何地方的GUI。
如果是我,我会抛出一个GUI监听的事件来显示错误信息。或者,您可以将SwingWorker的调用包装在try catch中并在那里显示对话框。
答案 3 :(得分:0)
首先:对不起,简短的回答,没有太多的时间。
我遇到了同样的问题:希望从工作人员中发布到System.out
。
简短回答:如果您使用execute()
方法,则不会阻止您的应用
问题是如果你按原样执行工作程序就没有阻塞:后台任务。
class MyWorker extend SwingWorker<Void, Void>{
@Override
protected Void doInBackground() throws ... {
// your logic here and a message to a stream
System.out.println("from my worker, with love");
// ...
try {
throw new Exception("Whoops, this is an exception from within the worker");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
现在,您将调用此worker创建一个新实例,然后调用execute()
方法。但是为了节省你一些时间:你可能想知道你的工作完成的时间,所以你需要注册一个属性更改监听器,这很简单:
class MyListener implements PropertyChangeListener{
@Override
public void propertyChange(PropertyChangeEvent evt){
if(evt.getPropertyName().equals("state") && evt.getNewValue().equals(SwingWorker.StateValue.DONE)){
System.out.println("The worker is done");
}
}
}
并将所有内容放在main()
:
public void main(...){
MyWorker w = new MyWorker();
MyListener l = new MyListener();
w.addPropertyChangeListener(l);
w.execute();
}