I have a Java3D scenegraph update task which takes 3-4 seconds on my laptop to complete. During this time I want a window showing up, asking the user to wait until the job completes. I have a simelar situation which takes longer and my implementation with a SwingWorker works fine. But when I apply the code to this update operation the dialog doesn't show up at all.
Here is the WaitDialog which I want to show (I also tried to inherit from JDialog - no change)
public class WaitDialog extends JFrame {
private static final long serialVersionUID = 1L;
protected int rows = 2;
protected int cols= 1;
protected int rowSpace= 12;
protected int colSpace= 12;
public WaitDialog(Component parent, String message) {
JPanel panel = new JPanel(new GridLayout(rows, cols, rowSpace, colSpace));
panel.setBorder( new EmptyBorder(12, 12, 12, 12) );
panel.add(new JLabel(message), BorderLayout.CENTER);
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
panel.add(progressBar);
setUndecorated(true);
setAlwaysOnTop(true);
getContentPane().add(panel);
pack();
setLocationRelativeTo(parent);
setVisible(true);
}
public void close() {
setVisible(false);
dispose();
}
}
The method that gives me headache looks like this...
public Result doIt(String fileName) throws Exception {
WaitDialog waitDialog = new WaitDialog(null, "Update...");
InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));
Result result = ansicht.calculateResult(inputStream); // Java3D calculation
waitDialog.close();
return result;
}
In this version, the waitDialog is not shown but calculteResult works fine. Therefore, as indicate above, I copied the working logic from another place, which looks like this...
public Result doIt(String fileName) throws Exception {
WaitDialog waitDialog = new WaitDialog(null, "Update...");
SwingWorker<Result,Void> worker = new SwingWorker<Result,Void>() {
@Override
protected Result doInBackground() throws Exception {
InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));
Result result = ansicht.calculateResult(inputStream); // Java3D calculation
return result;
}
@Override
protected void done() {
waitDialog.close();
}
};
worker.execute();
Result result = worker.get();
return result;
}
which shows no effect. No message shown and calculateResult works still fine. So I looked in the web what alternatives I might have and tried this...
public Result doIt(String fileName) throws Exception {
WaitDialog waitDialog = new WaitDialog(null, "Update...");
InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));
SwingUtilities.invokeAndWait(() -> {
try {
result = ansicht.calculateResult(inputStream); // Java3D calculation
} catch (Exception e) {
e.printStackTrace();
}
});
waitDialog.close();
return result;
}
result being now a Class variable. This version shows the wait dialog, but the calculateResult call is not coming back and the dialog doesn't disappear.
I also tried a version with an old fashioned Thread, which I found in the web...
public Result doIt(String fileName) throws Exception {
WaitDialog waitDialog = new WaitDialog(null, "Update...");
Thread thread = new Thread(() -> {
SwingUtilities.invokeAndWait(() -> {
try {
InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));
result = ansicht.calculateResult(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
});
thread.start();
while(thread.isAlive()) {};
waitDialog.close();
return result;
}
also not doing what I want.
Can you please advise me how to do this? Thank you in advance.
The way swing works is you have the Event Dispatch Thread (EDT) that is constantly running and processing GUI events. When you have a long running task, you run it on a different thread, then tell the EDT that your are finished.
Is "doIt" being called on the EDT? eg did you start it from an event like a button? I am going to assume it is.
All of your versions are blocking "doIt" until after the result is finished. You need to let doIt finish. I would suggest a call back.
Then in second version you can update it.
This is the worst version of your code.
That you are literally posting your long running task to the EDT and blocking the current thread, which I suspect is also the EDT.