Since you're using a JDialog
to manage the SwingWorker
, you can actual use the modal state of the dialog to you advantage.
Essentially, when a dialog is modal, it will block the code execution where the dialog is made visible. It will block until the dialog is hidden, at which time, the code will continue to execute.
So, you can disable the button before the dialog is made visible and re-enable it when it's closed.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Go");
add(btn);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
btn.setEnabled(false);
SomeWorkerDialog worker = new SomeWorkerDialog(TestPane.this);
// This is just so we can see the button ;)
Point point = btn.getLocationOnScreen();
worker.setLocation(worker.getX(), point.y + btn.getHeight());
worker.setVisible(true);
btn.setEnabled(true);
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class SomeWorkerDialog extends JDialog {
private JProgressBar progressBar;
private SomeWorkerSomeWhere worker;
public SomeWorkerDialog(JComponent parent) {
super(SwingUtilities.getWindowAncestor(parent), "Working Hard", DEFAULT_MODALITY_TYPE);
progressBar = new JProgressBar();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.insets = new Insets(10, 10, 10, 10);
add(progressBar, gbc);
worker = new SomeWorkerSomeWhere();
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
switch (name) {
case "state":
switch (worker.getState()) {
case DONE:
setVisible(false);
break;
}
break;
case "progress":
progressBar.setValue(worker.getProgress());
break;
}
}
});
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
worker.execute();
}
@Override
public void windowClosed(WindowEvent e) {
worker.cancel(true);
}
});
pack();
setLocationRelativeTo(parent);
}
}
public class SomeWorkerSomeWhere extends SwingWorker {
@Override
protected Object doInBackground() throws Exception {
for (int index = 0; index < 100 && !isCancelled(); index++) {
setProgress(index);
Thread.sleep(10);
}
return "AllDone";
}
}
}
Update
To get the value returned by the worked, you can add a method to the dialog which returns the calculated value...
public String getValue() throws Exception {
return worker.get()
}
So, once the dialog is closed and the execution of your code continues, you can enable the components you want and call the getValue
method
You can also store the result when the state changes and the PropertyChangeListener is notified
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…