In this post, I’ll show you how to develop a pop-up progress bar for Google Web Toolkit. In GWT applications, you may have to call a long-running process on the server and you’d like to give the user visual feedback that the process is running. In our case, we will create a pop-up progress bar that shows the user that the process is running. See the screenshot below.
For this application, we will make use of the SmartGWT framework. The SmartGWT framework includes a collection of nifty UI components that you can leverage in your GWT application. I would recommend that you take a look at the SmartGWT showcase app (very impressive). In fact, SmartGWT is more than just a collection of UI components, it includes an entire server infrastructure and has support for data binding, database access and more. But in this app, we’ll just use the UI components.
Creating the Progress Bar Window
We will create a new class for the Progress Bar Window. The class will have a constructor to set the title and message of the window. The title appears in the title bar and the message appears in the center. In the screenshot below, the title is “Demo” and the message is “Loading data…”.
The coding for this window involves laying out the components. The window is composed of a label for the message and a Progressbar component. The Progressbar component is from the SmartGWT framework.
[code]
package com.luv2code.progressbar.client;
import com.google.gwt.user.client.Timer;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Progressbar;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.layout.VLayout;
/**
* A progress bar window to represent the progress of a lengthy operation. The window is modal.
*
* Usage example
*
* progressBarWindow = new ProgressBarWindow("Searching", "Searching for data…");
* progressBarWindow.show();
*
* // later after lengthy process is finished
* progressBarWindow.hide();
*
*
* @author Chad Darby
*/
public class ProgressBarWindow extends Window {
private static final int REPEAT_INTERVAL = 250;
private static final int PROGRESS_VALUE_RANGE = 10;
private static final int MAX_VALUE = 100;
private Timer timer;
private Progressbar progressBar;
public ProgressBarWindow() {
this("Processing…");
}
/**
* Constructor
*
* @param message
*/
public ProgressBarWindow(String message) {
this("Processing", message);
}
/**
* Constructor
*
* @param title
* @param message
*/
public ProgressBarWindow(String title, String message) {
setShowModalMask(false);
buildGui(title, message);
}
/**
* Build the GUI components
*
* @param title
* @param message
*/
private void buildGui(String title, String message) {
setAutoSize(true);
setTitle(title);
setWidth(300);
centerInPage();
setCanDragReposition(true);
setCanDragResize(false);
setIsModal(true);
this.setShowMaximizeButton(false);
this.setShowMinimizeButton(false);
VLayout layout = new VLayout();
layout.setWidth100();
layout.setPadding(5);
addItem(layout);
Label messageLabel = new Label(message);
messageLabel.setWidth100();
messageLabel.setHeight(40);
layout.addMember(messageLabel);
progressBar = new Progressbar();
progressBar.setHeight(24);
progressBar.setVertical(false);
layout.addMember(progressBar);
}
/**
* Starts the progress timer
*/
private void startTimer() {
timer = new ProgressTimer();
timer.scheduleRepeating(REPEAT_INTERVAL);
}
@Override
public void show() {
super.show();
startTimer();
}
@Override
public void hide() {
super.hide();
stopTimer();
}
/**
* Stop the timer
*/
public void stopTimer() {
timer.cancel();
}
/**
* A timer that updates the progress bar
*/
class ProgressTimer extends Timer {
int value;
@Override
public void run() {
value += getRandomValue(PROGRESS_VALUE_RANGE);
if (value > MAX_VALUE) {
progressBar.setPercentDone(MAX_VALUE);
value = 0;
} else {
progressBar.setPercentDone(value);
}
}
/**
* Get random value for a given range
*
* @param range
* @return
*/
protected int getRandomValue(int range) {
return (int) (range * Math.random());
}
}
}
[/code]
In the code above, the class has three constructors to set the values for the window title and message label. The buildGui() method handles the layout of the components. The method sets the positioning of the window in the center also makes the window modal, to prevent the user from clicking elsewhere in the application. The buildGui() method also adds the label and progress bar components to the layout.
This progress bar window is an indeterminate progress bar. This means that we do not know how long the server process will take. We could provide hooks to poll the server side process, but in this scenario, the server-side process is a black box, we simply start the process and wait for it to finish. In order to simulate activity, we will run a background timer to update the progress bar percentage done. This functionality is handled in the ProgressTimer class. The progress bar starts with percentage done at 0% and then we run the timer to frequently increment the percentage done. In order to give it a bit of realism, we’ll add a random number to the percentage each time. So it seems like the work is moving faster/slower. In the event that we exceed the max value of the progress bar (100%), then we reset the value and continue.
Usage Example
Now that we’ve developed the progress bar, let’s take a look at how we will use it. When the user clicks a button in our UI, we will use GWT-RPC to make a call to the server. This method call may take a while to execute. For example, it could call a time-consuming database query, external web service call or just a computationally intensive operation. During this process, we will display a pop-up window to show the user progress. Once the process is finished then we will hide the window. Based on this information, we will have the following pseudo-code
[code]
In client UI event handler
Display progress bar window
Call long-running process on the server
Once process finishes, close progress bar window
[/code]
The screenshot below shows what happens when the user clicks on the “Send” button.
Let’s setup a click handler on the send button.
[code]
/**
* This is the entry point method.
*/
public void onModuleLoad() {
Button sendButton = new Button("Send");
nameField = new TextItem("gwtUser", "Please enter your name");
nameField.setWrapTitle(false);
…
// Add a handler to send the name to the server
SendButtonClickHandler sendButtonClickHandler = new SendButtonClickHandler();
sendButton.addClickHandler(sendButtonClickHandler);
}
[/code]
The real work is handled in the client-side click handler:
[code]
// Create a handler for the sendButton and nameField
class SendButtonClickHandler implements ClickHandler {
/**
* Fired when the user clicks on the sendButton.
*/
public void onClick(ClickEvent event) {
String textToServer = nameField.getValueAsString();
String title = "Demo";
String message = "Loading data…";
ProgressBarWindow progressBarWindow = new ProgressBarWindow(title, message);
progressBarWindow.show();
// Then, we send the input to the server.
greetingService.greetServer(textToServer, new GreetServerCallback(progressBarWindow));
}
}
[/code]
In the code above, we create the progress bar window and display it. Next, we make the call to our remote service, in this example it is greetingService.greetServer(). Here, I’m using a modified version of the GWT starter application codebase (greetingService).
The one missing link is the call back. When the server process completes, we need to clean up by closing the window. The code for the callback is next.
[code]
class GreetServerCallback implements AsyncCallback {
ProgressBarWindow progressBarWindow;
GreetServerCallback(ProgressBarWindow theProgressBarWindow) {
progressBarWindow = theProgressBarWindow;
}
public void onFailure(Throwable caught) {
progressBarWindow.hide();
// Show the RPC error message to the user
SC.say("Server response: " + caught.getMessage());
}
public void onSuccess(String result) {
progressBarWindow.hide();
// Show the server response to the user
SC.say("Server response: " + result);
}
}
[/code]
The callback has a handle to the same ProgressBarWindow that was displayed for this button click. In the implementation of the callback it is important to close the progress bar window for success/failure. The methods also make use of a SmartGWT feature, “SC.say”, which displays a JavaScript alert box.
Source Code
The source code is available for download.
That’s about it. We created the progress bar window and then used the window in our client application.
Enjoy!
Very informative (and also helpful). Thanks.