O'Reilly logo

Swing Hacks by Chris Adamson, Joshua Marinacci

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

470
|
Chapter 12, Miscellany
#93 Code Models That Don’t Block
HACK
Exposing the Threading
But what if a caller wants to manage threading? You might want to at least
expose the fact that a thread is still updating and have the rest of your code
be aware of that state.
Notice that the
NonBlockingURLDocument exposes a pair of extra methods—
isAlive( ) and getProgress( )—that aren’t required by Document or anything
else in
javax.swing.text. These are extra methods I tossed into the demo to
support the progress bar mentioned earlier in this hack.
The strategy here is to have an outside caller periodically check in on the
NonBlockingURLDocument, get its progress, and update a progress bar. Notice I
said periodically: this is a job for
javax.swing.Timer! Using the Swing timer,
you get regular callbacks, and your code is guaranteed to be on the event-
dispatch thread.
So, uncomment the
makeProgressBarUpdaterFor( ) call shown earlier, and
add this implementation of that method, along with a helper method:
Figure 12-8. Progressive self-update of a JTextArea’s document
Code Models That Don’t Block #93
Chapter 12, Miscellany
|
471
HACK
private void makeProgressBarUpdaterFor (NonBlockingURLDocument nbud) {
final NonBlockingURLDocument updatingDoc = nbud;
updateProgressBar (0);
ActionListener callback = new ActionListener( ) {
public void actionPerformed (ActionEvent ev) {
progressBar.setEnabled (true);
int progress = (int) (updatingDoc.getProgress( ) * 100);
updateProgressBar (progress);
if (! updatingDoc.isAlive( ))
progressBarUpdater.stop( );
}
};
progressBarUpdater = new javax.swing.Timer (2000, callback);
progressBarUpdater.start( );
}
private void updateProgressBar (int progress) {
// System.out.println ("update progress bar: " + progress);
if (progress > 0) {
progressBar.setValue (progress);
}
else
progressBar.setEnabled (false);
}
The makeProgressBarUpdaterFor( ) method creates a Timer that calls back to
the given
ActionListener every two seconds. The ActionListener gets the
progress from the
NonBlockingURLDocument and calls updateProgressBar( ),
which updates the progress bar if the value is positive, and disables the bar if
it’s negative. Also, if the document is no longer loading, the callback stops
the
Timer.
You might be thinking “why would I have to check for negative progress?”
As it turns out, it’s an unfortunate implementation detail: a lot of web serv-
ers send
-1, meaning unknown, as the HTTP content-length header. If you
look around, you’ll find sites that do send a valid content length.
Figure 12-9 shows an incremental load of http://www.oreilly.com/.
This approach used URLs and
Documents, but the approach is widely appli-
cable to other kinds of models—list models, tables models, etc.—and would
be well suited to other kinds of slow-to-load data. It should be straight-
forward to see how you could take this approach to create, say, a
TableModel
that’s passed a java.sql.Connection and populates its rows progressively
with database queries, without blocking the AWT and without making the
user wait to see the first few rows of data.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required