My first Vaadin app is coming along. Slowly, but at least it’s coming along. A new wrinkle: I’d like to have a “wait” cursor or spinner to appear during a long database call. Take the following scenario:
The TreeTable above shows March 7th’s jobs. I have it wired up so that if you click on a day in the calendar at the bottom, the TreeTable updates to show all the jobs that ship on that date. This means retrieving data from a linked-up SQL Server, which takes a good couple of seconds.
During this time there is no indication to the user that data is being retrieved. I would like to change that. How can this be done? I’ve heard that, to do this, I must spawn a new thread. Yet I’ve also heard that spawning background threads is a big no-no with Java EE, difficult with Servlets, and Tomcat doesn’t have a thread pool that is usable. (Please bear in mind that I am still learning. i.e., I don’t really even know how to spawn threads in Java.)
Any time you have to perform a long-running task it’s a good idea to execute it in a separate thread. In your case using Java threads directly sounds like a good fit.
In Vaadin applications, when your listener (e.g.
ClickListener or
ValueChangeListener ) gets invoked you can do the following:
Add a spinner to the UI. An indeterminate
ProgressIndicator is a good option:
progressIndicator.
setIndeterminate(true) .
Run the long-running task in a separate thread. At this point the first thread (the one invoking the listener) finnishes and the user is able to see the spinner.
Once the “separate thread” complete the long-running task, remove the spinner with the help of the
UI.access(Runnable)
Thank you for setting me on the right path, @Allejandro (or so I’ll assume it is, anyway), especially with that link to your example project. Unfortunately, I believe I still need some guidance, as it is only partially working currently. Also, I apologize for taking so long in replying to this; other priorities came up in the interim.
Okay, so I followed your GitHub example and understood most of it. I’m still struggling with the concept of Java 8’s Lambdas, but I’m sure I’ll get by for now. The primary issue I’m running into is that click #1 on the InlineDateField shows the spinning progress indicator, but the Treetable doesn’t appear to update. Click #2 (on a different date) on the InlineDateField now shows the correct date’s info in the Treetable and the spinner disappears after a short moment. Click #3 acts the same as Click #1, and the whole process continues this pattern.
Here’s the relevant portions:
[...]
/**
* Calendar.
*/
InlineDateField cal = new InlineDateField();
cal.addValueChangeListener(this::changeDay);
[...]
private void changeDay (ValueChangeEvent event) {
selectedDate = (Date) event.getProperty().getValue();
logger.log(Level.INFO, "Calendar Value changed. New value: " + selectedDate.toString());
progressBar.setVisible(true); // Give the user some visual hint abount loading taking place
// Perform the data load in a separate thread
loadDataInNewThread();
}
private void loadDataInNewThread() {
new Thread(() -> {
// This is needed because we are modifying the UI from a different thread:
UI.getCurrent().access(() -> {
treeTable.changeDayTo(selectedDate);
progressBar.setVisible(false);
});
}).start();
}
[...]
The first few lines are a small part of the class’ constructor. (If I’m understanding the term correctly in this context, that is.) The two methods listed are modifications of the ones shown in your Github example. The big difference in mine is that all of the Treetable-updating code lies in the .changeDayTo() method, which is actually a part of my custom Treetable class. (I was always taught to keep all of the properties and methods specific to a class with that class.)
It still gets data to/from a SQL Server database, so it cannot be run as-is, I’m afraid. Nevertheless, it should be enough for someone like you, @Alejandro, to figure out why your suggestion is not working. Please let me know as soon as you get a chance.
I’m afraid I am not very familiar with annotations. And after looking at the API doc for that annotation, I’m not sure how to properly implement it. (I never learned how to read Javadocs, unfortunately.)
Shall I just add it to the top with the other two annotations, like so?:
[...]
@SuppressWarnings("serial")
@Theme("scheduling")
@Push
public class SchedulingUI extends UI {
[...]
Excellent! That does appear to work, indeed. Thank you for your help, @Alejandro!
Now I just need to figure out the best way of displaying a wait spinner to inform the user that the app is retrieving info and to be patient. Also deal with a bunch of exceptions that have decided to start appearing after adding in that annotation. Never a dull moment!