CubbyHole Example

Chapter 9 - Threads and Swing

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Using SwingUtilities.invokeLater()
The SwingUtilities class has another static method available to use to put references to blocks of code onto the event queue:
public static void invokeLater (Runnable target)
The SwingUtilities.invokeLater() method works like SwingUtilities.invokeAndWait() except for the fact that it puts the request on the event queue and returns right away . The invokeLater() method does not wait for the block of code inside the Runnable referred to by target to execute. This allows the thread that posted the request to move on to other activities.
  Note Just as with invokeAndWait() , a new thread is not created when Runnable is used with SwingUtilities.invokeLater() .
This example is just like the one used for invokeAndWait() , but instead shows the changes necessary to use invokeLater() . Suppose a JLabel component has been rendered on screen with some text:
label = new JLabel(// ...
If a thread other than the event thread needs to call setText() on label to change it, you should do the following. First, create an instance of Runnable to do the work:
Runnable setTextRun = new Runnable() {
        public void run() {
            try {
                label. setText (// ...
            } catch ( Exception x) {
                x.printStackTrace();
            }
        }
    };
Be sure to catch all exceptions inside run() because unlike invokeAndWait() , invokeLater() does not have an automatic mechanism to propagate the exception back to the thread that called invokeLater() . Instead of simply printing a stack trace, you could have the event thread store the exception and notify another thread that an exception occurred.
Next, pass the Runnable instance referred to by setTextRun to invokeLater() :
SwingUtilities. invokeLater (setTextRun);
This call returns right away and does not throw any exceptions. When the event thread has processed all of the pending events, it invokes the run() method of setTextRun .
InvokeLaterDemo (see Listing 9.4) is a complete example (based on InvokeAndWaitDemo ) that demonstrates the use of SwingUtilities.invokeLater() .
Listing 9.4  InvokeLaterDemo.javaUsing SwingUtilities.invokeLater()
1: import java.awt.*;
2: import java.awt.event.*;
3: import javax.swing.*;
4:
5: public class InvokeLaterDemo extends Object {
6:     private static void print(String msg) {
7:         String name = Thread.currentThread().getName();
8:         System.out.println(name + : + msg);
9:     }
10:
11:     public static void main(String[] args) {
12:         final JLabel label = new JLabel();
13:
14:         JPanel panel = new JPanel(new FlowLayout());
15:         panel.add(label);
16:
17:         JFrame f = new JFrame(InvokeLaterDemo);
18:         f.setContentPane(panel);
19:         f.setSize(300, 100);
20:         f.setVisible(true);
21:
22:         try {
23:             print(sleeping for 3 seconds);
24:             Thread.sleep(3000);
25:         } catch (InterruptedException ix) {
26:             print( interrupted while sleeping);
27:         }
28:
29:         print(creating code block for event thread);
30:         Runnable setTextRun = new Runnable() {
31:                 public void run() {
32:                     try {
33:                         Thread.sleep(100); // for emphasis
34:                         print(about to do setText());
35:                         label.setText (New text!);
36:                     } catch ( Exception x) {
37:                         x.printStackTrace();
38:                     }
39:                 }
40:             };
41:
42:         print(about to invokeLater());
43:         SwingUtilities.invokeLater(setTextRun);
44:         print(back from invokeLater());
45:     }
46: }
The main thread creates the GUI (lines 1219) and invokes setVisible() on the JFrame (line 20). From that point on, only the event thread should make changes to the GUI .
After sleeping for 3 seconds (line 24), the main thread wants to change the text displayed in label . To safely do this, the main thread creates a bundle of code in setTextRun (lines 3040). Inside the run() method, a try/catch block is used to capture any exceptions that might be thrown so that run() itself does not end up throwing any exceptions (lines 3238). A very short sleep of 0.1 seconds (line 33) is used to momentarily slow the event thread to clearly show that the invokeLater() call returns right away. In real-world code there would not be any need for this sleep. Eventually, the event thread invokes the setText() method on label (line 35).
After setting up this code block, the main thread calls SwingUtilities.invokeLater() , passing in setTextRun (line 43). Inside invokeLater() , the setTextRun reference is put onto the event queue and then the main thread returns right away . When all of the events that were ahead of it in the queue have been processed, the event thread invokes the run() method of setTextRun .
Listing 9.5 shows the output produced when InvokeLaterDemo is run. Your output should match. In addition, a frame is drawn on the screen, but it doesnt show anything other than the fact that the label does indeed change.
Listing 9.5  Output from InvokeLaterDemo
1: main: sleeping for 3 seconds
2: main: creating code block for event thread
3: main: about to invokeLater()
4: main: back from invokeLater()
5: AWT-EventQueue-0 : about to do setText ()
The main thread calls (line 3) and returns from (line 4) invokeLater() before the event thread gets a chance to invoke setText() (line 5). This is the exact asynchronous behavior that was desired.
  Note Unlike SwingUtilities.invokeAndWait() , the event thread is permitted to call SwingUtilities.invokeLater() . However, there isnt any value to doing so because the event thread can change the components 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