Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Java Tip 87: Automate the hourglass cursor

Force Java's UI event queue to decide when to show the hourglass cursor

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone

Page 2 of 3

29:         synchronized void startTimer(Object source) {
30:             this.source = source;
31:             notify();
32:         }


Analyzing the timer thread

Now look at the implementation of the run() method for the timer thread, the real workhorse of the thread. First note that the entire run() method is synchronized, as are both the startTimer() and stopTimer() methods. This synchronization prevents multithreading race conditions by letting the startTimer() or stopTimer() methods execute only when the run() method enters either of the two wait() statements to release the monitor. After the timing thread starts, it waits indefinitely at line 47 to be notified and awakened by the startTimer() method.

46:                     //wait for notification from startTimer()
47:                     wait();


After receiving notification from the startTimer() method, the timing thread pauses again at the next statement.

49:                     //wait for event processing to reach the threshold, or
50:                     //interruption from stopTimer()
51:                     wait(delay);


Here, the thread waits for the specified length of time to pass. Once it reaches this statement, there are only two possible paths of execution. The event currently being dispatched by your event queue may return from processing and interrupt the thread, at which point an InterruptedException will be thrown and will force the thread to wrap around to the top of the loop and wait for the next event. However, if processing takes longer than your specified delay period, your timer thread will awaken on its own and continue executing the following code.

53:                     if (source instanceof Component)
54:                         parent = 
SwingUtilities.getRoot((Component)source);
55:                     else if (source instanceof MenuComponent) {
56:                         MenuContainer mParent =
57:                                 ((MenuComponent)source).getParent();
58:                         if (mParent instanceof Component)
59:                             parent = SwingUtilities.getRoot(
60:                                     (Component)mParent);
61:                     }
62: 
63:                     if (parent != null && parent.isShowing())
64:                         parent.setCursor(
65:                                 Cursor.getPredefinedCursor(
66:                                     Cursor.WAIT_CURSOR));


Here, you first determine whether the source is a java.awt.Component or a java.awt.MenuComponent, both of which indicate that you can eventually locate a java.awt.Window whose cursor you need to change. Note that you must handle a java.awt.MenuComponent as a special case because it does not extend java.awt.Component like the other UI classes in the AWT (Abstract Windowing Toolkit) package. Then a Swing utility method locates the window that contains the source component. Once you have that parent window, you can change that window's cursor to an hourglass. You can call the Component.setCursor() method outside the normal event-dispatch thread because, as a quick perusal of the java.awt.Component source code will reveal, setCursor() is a synchronized method.

You may notice that this timing thread waits until the last moment before trying to find the source object's parent window. Although it may seem reasonable to find the parent within the startTimer() method, this particular implementation enjoys a performance advantage. Hundreds of events can flow through your queue if you simply move the mouse cursor around a window, so you want to introduce as little processing overhead as possible from your event queue. You can accomplish this by performing extra processing only when absolutely necessary, including finding the source object's parent window. In your timer thread, you need to find the parent window only if the specified delay passes and you are forced to display the hourglass cursor.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources