与swingworker的对话是鸡/蛋

我试图通过不在主线程(EDT)上执行长任务来遵循Java最佳实践。 所以我打算使用带有Modal Dialog的swingWorker。 这样,modal dialog阻止用户执行任何操作,直到该任务完成,并且我可以在进程发生时更新对话框的状态。

现在的问题是,使用modal dialog,它不仅会阻止用户,而且在调用setVisible之后也不会阻止任何内容

所以,如果我这样做

dialog.setVisible(true); new SwingWorkerTask().execute(); //This does not get called 

如果我这样做

 new SwingWorkerTask().execute(); dialog.setVisible(true); // Well what the point of setting visible after the fact. 

那么如何在任务发生时阻止用户操作并显示对话框?

谢谢

如果你做到这一点,它只是一个鸡/蛋。 您可以在EDT上构造所有Swing对象,然后让SwingWorker (或任何其他线程)通过指示EDT通过SwingUtilities.invokeLater(Runnable)执行它们来管理所有更新。

 import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; public class RudeProgressBar extends JFrame { private JButton button; public RudeProgressBar() { setTitle("Rude Progress Bar"); setDefaultCloseOperation(EXIT_ON_CLOSE); setLayout(new BorderLayout()); button = new JButton("Do teh work"); add(button, BorderLayout.SOUTH); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JDialog dialog = new JDialog(RudeProgressBar.this, true); dialog.setTitle("Doing teh work"); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); final JProgressBar progressBar = new JProgressBar(0, 100); dialog.setLayout(new BorderLayout()); dialog.add(progressBar); dialog.setSize(100, 100); dialog.setLocationRelativeTo(RudeProgressBar.this); MyTask task = new MyTask(dialog); task.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { progressBar.setValue((Integer)evt.getNewValue()); } } }); task.execute(); } }); setSize(200, 200); setLocationRelativeTo(null); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new RudeProgressBar().setVisible(true); } }); } private class MyTask extends SwingWorker { private final JDialog dialog; public MyTask(JDialog dialog) { this.dialog = dialog; } @Override protected Void doInBackground() throws Exception { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { dialog.setVisible(true); } }); int progress = 0; for (int i = 0; i < 5; i++) { Thread.sleep(1000); setProgress(progress += 20); } return null; } @Override protected void done() { dialog.setVisible(false); dialog.dispose(); } } } 

如果您担心在SwingWorker.doInBackground之后可能会执行invokeLater实现(在SwingWorker.doInBackground ),只需将代码放入另一个invokeLater 。 通过执行此操作,您可以对EDT的Runnable实现进行排队,以便按特定顺序执行它们。 即使从EDT本身调用此方法,也会发生排队。

请注意,如果你看看SwingWorker实现,你会发现它依赖于javax.swing.Timer来执行done()Timer本身调用了invokeLater ,所以再次调用它就done了什么。 但是,如果你这样做,那就什么都不会错。

您可以尝试使用SwingUtilities.invokeLater和SwingUtilities.invokeAndWait而不是swingWorker。

此外, 该主题可能有用。