I have put together an application that opens text files and allows users to edit them (eg: text editor)
Some text files can be arbitrarily large, so it would take some time to open them. I have added a progress bar to inform the user that stuff is actually happening, and am using a swing worker to perform the actual file loading, giving it a reference to a text area to dump all the text.
I also have a flag in the main application called isFileLoaded
which is true if there's a file open, and false otherwise. Ideally, the swing worker should set that value after it finishes loading the file and doing any processing that it needs to do.
I have written the swing worker as a separate class, so it's not nested inside my main Frame class that holds all of the GUI logic, mainly because I do not like to define classes inside classes purely for aesthetic reasons. As such, I am currently passing a reference to the entire Frame to the swing worker and letting it set the value of the flag.
Is this a good way to do things? Are there better ways?
Consider rather adding a PropertyChangeListener
which holds a reference to your Frame
(an anonymous inner-class would be just fine for that matter) and which listens to the "state"
property. The value of the event will be equal to StateValue.DONE
when the SwingWorker
has finished.
Here is a fully working example:
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.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.SwingWorker.StateValue;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestSwingWorker {
private JProgressBar progressBar;
protected void initUI() {
final JFrame frame = new JFrame();
frame.setTitle(TestSwingWorker.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Clik me to start work");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doWork();
}
});
progressBar = new JProgressBar(0, 100);
frame.add(progressBar, BorderLayout.NORTH);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
private boolean someFlag;
protected void doWork() {
SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
@Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < 100; i++) {
// Simulates work
Thread.sleep(10);
publish(i);
}
return null;
}
@Override
protected void process(List<Integer> chunks) {
progressBar.setValue(chunks.get(chunks.size() - 1));
}
@Override
protected void done() {
progressBar.setValue(100);
progressBar.setStringPainted(true);
progressBar.setString("Done");
}
};
worker.getPropertyChangeSupport().addPropertyChangeListener("state", new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (StateValue.DONE.equals(evt.getNewValue())) {
someFlag = true;
}
}
});
worker.execute();
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestSwingWorker().initUI();
}
});
}
}