我试图通过不在主线程(EDT)上执行长任务来遵循Java最佳实践。所以我打算使用带有Modal Dialog的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.
那么如何在任务发生时阻止用户操作并显示对话框?
谢谢
答案 0 :(得分:1)
如果你做的话,它只是一只鸡/蛋。您可以在EDT上构建所有Swing对象,然后让Function DrawDiagram()
Dim x As Long
Dim diaLst As MSForms.ListBox
Set diaLst = ActiveSheet.ListBoxes("DiaList")
' find selected trends in List Box
For x = 1 To diaLst.ListCount
If diaLst.Selected(x) = True Then
MsgBox x
End If
Next x
End Function
(或任何其他线程)管理所有更新,方法是指示EDT通过SwingUtilities.invokeLater(Runnable)
执行它们。
SwingWorker
如果您担心可能会在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
即可。通过执行此操作,您可以将EDT的invokeLater
实现排入队列,以便按特定顺序执行它们。即使从EDT本身调用此方法,也会发生排队。
请注意,如果您查看Runnable
实施,您会发现它依赖于javax.swing.Timer
来执行SwingWorker
而done()
本身会调用{ {1}},因此再次在Timer
内调用它无关紧要。但是,如果你这样做,那就没有错。
答案 1 :(得分:0)
您可以尝试SwingUtilities.invokeLater和SwingUtilities.invokeAndWait而不是swingWorker。
此外,this topic可能有用。