Reputation: 38
I am currently working on a small application to display/save notes. The content of each note is stored inside a .properties file on my hard drive after closing the application. If you open the application again then all notes are loading inside the application.
While this loading process is taking place, I show a dialog box with a progressbar that indicates the state of the process. Furthermore, I display a GlassPane so the user can’t interact with the GUI or crate/save notes while loading.
Following is my current Code for loading the notes:
public void load() {
new Thread() {
@Override
public void run() {
Properties data = new Properties();
FileInputStream iStream = null;
File[] files = sortPairs();
int fileIndex = -1;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
pnlGlass = new MyGlassPane();
infoText = new JTextField();
progBar = new JProgressBar(0,100);
progBar.setValue(0);
progBar.setStringPainted(true);
infoBox = new LoadInfoDialog(infoText,progBar);
infoBox.setLocationRelativeTo(gui);
infoBox.setVisible(true);
infoBox.setDefaultCloseOperation(infoBox.DO_NOTHING_ON_CLOSE);
pnlGlass.setOpaque(false);
pnlGlass.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent me) {
me.consume();
}
});
gui.setGlassPane(pnlGlass);
pnlGlass.setVisible(true);
pnlGlass.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
});
for (File file : files) {
if (file.isFile()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
iStream = new FileInputStream(file);
data.load(iStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (!(iStream == null)) {
try {
iStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String title = data.getProperty("title");
String text = data.getProperty("text");
String erstellt = data.getProperty("date");
String fileName = data.getProperty("filename");
Note note = new Note(text, title);
note.setFileName(fileName);
note.setDate(erstellt);
fileIndex++;
final int fileIndexFinal = fileIndex;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progBar.setValue(progBar.getValue() + 100 / fileCount);
infoText.setText("Lade Notizen, bitte warten..." + progBar.getValue() + "%");
noteModel.addNote(note);
System.out.println("Index:" + fileIndexFinal);
}
});
}
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
pnlGlass.setVisible(false);
infoBox.setVisible(false);
}
});
}
}.start();
}
I am sure that my solution is pretty ragged. After some research I figured that there is a class called "SwingWorker" for exactly this purpose (running Taks in background and update gui) BUT, how can I create my note (add Note-Object to my Model) from within the SwingWorker?
I know that I can update my progressbar using the publish and process methods but how can I create an object using the SwingWorker?
The loading process should do the following routine for every note:
Read content from .properties file -> create note Object -> show note in JList -> update progressbar.
Upvotes: 0
Views: 98
Reputation: 347184
Start by defining your core worker...
public class NotesLoader extends SwingWorker<List<Properties>, Properties> {
@Override
protected List<Properties> doInBackground() throws Exception {
List<Properties> notes = new ArrayList<>(25);
File[] files = new File(".").listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".properties");
}
});
for (File file : files) {
int count = 0;
try (Reader reader = new FileReader(file)) {
Properties note = new Properties();
note.load(reader);
notes.add(note);
publish(note);
setProgress((int) ((count / (double) files.length) * 100d));
}
}
return notes;
}
}
This simple scans the current working directory for .properties
files and tries to load them one at a time. When one is loaded, it is sent via the publish
method and the progress is updated via the setProgress
method.
Now, I devised a simple progress panel which looks like this...
public class LoadingPane extends JPanel {
private JLabel label;
private JProgressBar pb;
public LoadingPane() {
setLayout(new GridBagLayout());
setOpaque(false);
label = new JLabel("Loading, please wait");
pb = new JProgressBar();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
add(pb, gbc);
addMouseListener(new MouseAdapter() {
});
setFocusable(true);
}
public void setProgress(float progress) {
pb.setValue((int) (progress * 100f));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(128, 128, 128, 128));
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
}
}
This is important, as it has a setProgress
method
Now, we can use these two together to load the notes in the background and update the UI safely as the progress updates.
LoadingPane loadingPane = new LoadingPane();
JFrame frame = new JFrame("Testing");
frame.setGlassPane(loadingPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("I'll wait here okay"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
NotesLoader loader = new NotesLoader() {
@Override
protected void process(List<Properties> chunks) {
System.out.println(chunks.size() + " notes were loaded");
// Update you model??
}
};
loader.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
switch (name) {
case "state":
switch (loader.getState()) {
case STARTED:
frame.getGlassPane().setVisible(true);
frame.getGlassPane().requestFocusInWindow();
break;
case DONE:
frame.getGlassPane().setVisible(false);
try {
// Doubt your need the list, but it's good to do this
// incase there was an exception which occured during
// the running of the worker
List<Properties> notes = loader.get();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
// Maybe show an error message...
}
break;
}
break;
case "progress":
// I like working with normalised values :P
loadingPane.setProgress(((int)evt.getNewValue() / 100f));
break;
}
}
});
The example overrides the process
method, so you can get the notes as they are loaded, but equally, you could wait till the state changes to DONE
and get them all at once, it's up to you
Upvotes: 1