Early Notification

Chapter 9 - Threads and Swing

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Using SwingUtilities.invokeAndWait()
The developers of the Swing toolkit realized that there would be times when an external thread would need to make changes to Swing components . They created a mechanism that puts a reference to a chunk of code on the event queue. When the event thread gets to this code block, it executes the code. This way, the GUI can be changed inside this block of code by the event thread.
The SwingUtilities class has a static invokeAndWait() method available to use to put references to blocks of code onto the event queue:
public static void invokeAndWait (Runnable target)
        throws InterruptedException,
               InvocationTargetException
The parameter target is a reference to an instance of Runnable . In this case, the Runnable will not be passed to the constructor of Thread . The Runnable interface is simply being used as a means to identify the entry point for the event thread. Just as a newly spawned thread will invoke run() , the event thread will invoke run() when it has processed all the other events pending in the queue.
An InterruptedException is thrown if the thread that called invokeAndWait() is interrupted before the block of code referred to by target completes. An InvocationTargetException (a class in the java.lang.reflect package) is thrown if an uncaught exception is thrown by the code inside run() .
  Note A new thread is not created when Runnable is used with SwingUtilities.invokeAndWait() . The event thread will end up calling the run() method of the Runnable when its turn comes up on the event queue.
Suppose a JLabel component has been rendered on screen with some text:
label = new JLabel(// ...
Now, if a thread other than the event thread needs to call setText() on label to change it, the following should be done. First, create an instance of Runnable to do the work:
Runnable setTextRun = new Runnable() {
        public void run() {
            label. setText (// ...
        }
    };
Then pass the Runnable instance referred to by setTextRun to invokeAndWait() :
try {
    SwingUtilities.invokeAndWait(setTextRun);
} catch ( InterruptedException ix) {
    ix.printStackTrace();
} catch ( InvocationTargetException x) {
    x.printStackTrace();
}
The try/catch block is used to catch the two types of exception that might be thrown while waiting for the code inside the run() method of setTextRun to complete.
InvokeAndWaitDemo (see Listing 9.2) is a complete example that demonstrates the use of SwingUtilities.invokeAndWait() .
Listing 9.2  InvokeAndWaitDemo.javaUsing SwingUtilities.invokeAndWait()
1: import java.awt.*;
2: import java.awt.event.*;
3: import java.lang.reflect.*;
4: import javax.swing.*;
5:
6: public class InvokeAndWaitDemo extends Object {
7:     private static void print(String msg) {
8:         String name = Thread.currentThread().getName();
9:         System.out.println(name + : + msg);
10:     }
11:
12:     public static void main(String[] args) {
13:         final JLabel label = new JLabel();
14:
15:         JPanel panel = new JPanel(new FlowLayout());
16:         panel.add(label);
17:
18:         JFrame f = new JFrame(InvokeAndWaitDemo);
19:         f.setContentPane(panel);
20:         f.setSize(300, 100);
21:         f.setVisible(true);
22:
23:         try {
24:             print(sleeping for 3 seconds);
25:             Thread.sleep(3000);
26:
27:             print(creating code block for event thread);
28:             Runnable setTextRun = new Runnable() {
29:                     public void run() {
30:                         print(about to do setText());
31:                         label.setText (New text!);
32:                     }
33:                 };
34:            
35:             print(about to invokeAndWait());
36:             SwingUtilities.invokeAndWait(setTextRun);
37:             print(back from invokeAndWait());
38:         } catch ( InterruptedException ix) {
39:             print(interrupted while waiting on invokeAndWait());
40:         } catch ( InvocationTargetException x) {
41:             print(exception thrown from run());
42:         }
43:     }
44: }
Note that the java.lang.reflect package is imported (line 3) solely for InvocationTargetException . The main thread creates the GUI (lines 1320) and invokes setVisible() on the JFrame (line 21). From that point on, only the event thread should make changes to the GUI .
After sleeping for 3 seconds (line 25), the main thread wants to change the text displayed in label . To safely do this, the main thread must pass this work off to the event-handling thread. The main thread creates a bundle of code in setTextRun , which is an instance of Runnable (lines 2833). Inside the run() method, the setText() method is invoked on label (line 31). Ultimately, the event thread will end up invoking the setText() method inside this run() method.
The main thread then calls SwingUtilities.invokeAndWait() passing in setTextRun (line 36). Inside invokeAndWait() , the setTextRun reference is put onto the event queue. When all the events that were ahead of it in the queue have been processed, the event thread invokes the run() method of setTextRun . When the event thread returns from run() , it notifies the main thread that it has completed the work.
The event thread then goes back to reading events from the event queue. At the same time, the main thread returns from invokeAndWait() , indicating that the code block inside setTextRun has been run by the event thread.
Listing 9.3 shows the output produced when InvokeAndWaitDemo is run. In addition, a GUI frame appears, but that doesnt show anything other than the fact that the label changes when setText() is invoked.
Listing 9.3  Output from InvokeAndWaitDemo
1: main: sleeping for 3 seconds
2: main: creating code block for event thread
3: main: about to invokeAndWait()
4: AWT-EventQueue-0 : about to do setText ()
5: main: back from invokeAndWait()
The main thread announces that it is about to call invokeAndWait() (line 3). Next, the event thread ( AWT-EventQueue-0 ) reports that it is indeed the thread that is invoking and has returned from invokeAndWait() (line 5).
  Caution Do not call SwingUtilities.invokeAndWait() from the event thread. Doing so causes an instance of Error to be thrown. Even if this call were allowed, it would put the event thread into a deadlocked state. The event thread does not need the services of invokeAndWait() because it can make the changes directly.

Toc


Java Thread Programming
Java Thread Programming
ISBN: 0672315858
EAN: 2147483647
Year: 2005
Pages: 149
Authors: Paul Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net