I'm trying to learn SwingWorker
and I have this simple code running and working, but I can't figure out how to prompt a JOptionPane.showMessageDialog
when the task is complete. I've to tried to put
if (isDone())
JOptionPane.showMessageDialog(null, "Task Complete");
in different locations, but can't get anything to work. I've read that I may have to put it in the invokeLater()
for it to run in the EDT, I'm not really sure how to accomplish that.
I tried to have my SwingWorker
as a class member of my panel, but I can't instantiate it because it gets intantiaated in a listener. So I get a null pointer trying to put if (task.isDone())
in my invokeLater()
.
What is the proper way to accomplish this task?
I have an SSCCE here (all you do is enter a number and it prints my name that many times to a text area).
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.*;
public class RepeatNameSwingWorker extends JPanel {
private JProgressBar jpb = new JProgressBar(0, 100);
private JTextArea jtaNames = new JTextArea(20, 50);
private final JTextField jtfTimes = new JTextField(8);
private final JButton jbtExecute = new JButton("Execute");
private final JLabel jlblNumTimes = new JLabel("Enter number of times: ");
public RepeatNameSwingWorker(){
jpb.setStringPainted(true);
jtaNames.setLineWrap(true);
jtaNames.setWrapStyleWord(true);
JPanel panel = new JPanel();
panel.add(jlblNumTimes);
panel.add(jtfTimes);
panel.add(jbtExecute);
setLayout(new BorderLayout());
add(jpb, BorderLayout.NORTH);
add(new JScrollPane(jtaNames), BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
jbtExecute.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
RepeatNames task = new RepeatNames(
Integer.parseInt(jtfTimes.getText()), jtaNames);
task.addPropertyChangeListener(new PropertyChangeListener(){
@Override
public void propertyChange(PropertyChangeEvent e) {
if ("progress".equals(e.getPropertyName())) {
jpb.setValue((Integer)e.getNewValue());
}
}
});
task.execute();
if (task.isDone())
JOptionPane.showMessageDialog(null, "Task Complete");
}
});
}
static class RepeatNames extends SwingWorker<String, String>{
int times;
JTextArea result;
public RepeatNames(int times, JTextArea result) {
this.times = times;
this.result = result;
}
@Override
protected String doInBackground(){
publishNames(times);
return null;
}
@Override
protected void done() {
try {
result.append(get().toString()); // Display in text field
} catch (Exception ex) {
result.append(ex.getMessage());
}
}
@Override
protected void process(List<String> list) {
for (int i = 0; i < list.size(); i++) {
result.append(list.get(i) + " ");
}
}
private void publishNames(int n) {
int count = 0;
int number = 2;
while (count <= n) {
if (isPrime(number)) {
count++;
setProgress(100 * count / n);
publish("Paul");
}
number++;
}
}
private static boolean isPrime(int number) {
for (int divisor = 2; divisor <= number / 2; divisor++) {
if (number % divisor == 0) {
return false;
}
}
return true;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new RepeatNameSwingWorker());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
});
}
}
, but I can't figure out how to prompt a JOptionPane.showMessageDialog when the task is complete
Show the JOptionPane in the done() method.