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.

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.