我试图遵循 Java 最佳实践,不在主线程(EDT)上执行长时间任务。所以我计划使用带有模态对话框的 swingWorker。这样,模式对话框会阻止用户执行任何操作,直到该任务完成,并且我可以在该过程发生时更新对话框上的状态。
现在的问题是,对于模态对话框,它不仅会阻止用户,而且在调用 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) https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeLater%28java.lang.Runnable%29.
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<Void, Void> {
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();
}
}
}
如果您担心invokeLater
实施(内部SwingWorker.doInBackground
) 可能会在之后执行SwingWorker.done
,只需将代码放入done
进入另一个invokeLater
。通过这样做,您可以将您的Runnable
EDT 的实现以特定顺序执行它们。即使从 EDT 本身调用此方法,也会发生排队。
请注意,如果您看一下SwingWorker
实现,你会发现它依赖于javax.swing.Timer https://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html执行done()
和Timer
本身调用invokeLater
,所以在里面调用它done
再次等于什么也不做。不过,如果你这样做的话,不会有什么问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)