Overview

Chapter 9 - Threads and Swing

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Animating a Set of Images
Instead of scrolling one image across the face of a component as ScrollText does, a component can use an internal thread to step through a set of different images one image at a time. This set of images can be considered frames or slides. By flipping through the slides (or frames ), the internal thread creates animation.
In SlideShow (see Listing 9.9), a set of images is created and an internal thread loops through them at a rate of 10 images per second. In this case, an expanding yellow circle is drawn on a blue background, but you could use any set of images.
Listing 9.9  SlideShow.javaAnimation of a Set of Images
  1: import java.awt.*;
  2: import java.awt.image.*;
  3: import javax.swing.*;
  4:
  5: public class SlideShow extends JComponent {
  6:     private BufferedImage[] slide;
  7:     private Dimension slideSize;
  8:     private volatile int currSlide;
  9:
10:     private Thread internalThread;
11:     private volatile boolean noStopRequested;
12:
13:     public SlideShow() {
14:         currSlide = 0;
15:         slideSize = new Dimension(50, 50);
16:         buildSlides();
17:
18:         setMinimumSize(slideSize);
19:         setPreferredSize(slideSize);
20:         setMaximumSize(slideSize);
21:         setSize(slideSize);
22:
23:         noStopRequested = true;
24:         Runnable r = new Runnable() {
25:                 public void run() {
26:                     try {
27:                         runWork();
28:                     } catch (Exception x) {
29:                         // in case ANY exception slips through
30:                         x.printStackTrace();
31:                     }
32:                 }
33:             };
34:
35:         internalThread = new Thread(r, SlideShow);
36:         internalThread.start();
37:     }
38:
39:     private void buildSlides() {
40:         // Request that the drawing be done with anti-aliasing
41:         // turned on and the quality high.
42:         RenderingHints renderHints = new RenderingHints(
43:             RenderingHints.KEY_ANTIALIASING,
44:             RenderingHints.VALUE_ANTIALIAS_ON);
45:
46:         renderHints.put(
47:             RenderingHints.KEY_RENDERING,
48:             RenderingHints.VALUE_RENDER_QUALITY);
49:
50:         slide = new BufferedImage[20];
51:
52:         Color rectColor = new Color (100, 160, 250);   // blue
53:         Color circleColor = new Color(250, 250, 150); // yellow
54:
55:         for (int i = 0; i < slide.length; i++) {
56:             slide[i] = new BufferedImage(
57:                     slideSize.width,
58:                     slideSize.height,
59:                     BufferedImage.TYPE_INT_RGB);
60:
61:             Graphics2D g2 = slide[i].createGraphics();
62:             g2.setRenderingHints(renderHints);
63:
64:             g2.setColor(rectColor);
65:             g2.fillRect(0, 0, slideSize.width, slideSize.height);
66:
67:             g2.setColor(circleColor);
68:
69:             int diameter = 0;
70:             if (i < (slide.length / 2)) {
71:                 diameter = 5 + (8 * i);
72:             } else {
73:                 diameter = 5 + (8 *  (slide.length - i));
74:             }
75:
76:             int inset = (slideSize.width - diameter) / 2;
77:             g2.fillOval(inset, inset, diameter, diameter);
78:
79:             g2.setColor(Color.black);
80:             g2.drawRect(
81:                 0, 0, slideSize.width - 1, slideSize.height - 1);
82:
83:             g2.dispose();
84:         }
85:     }
86:
87:     public void paint(Graphics g) {
88:         g.drawImage(slide[currSlide], 0, 0, this);
89:     }
90:
91:     private void runWork() {
92:         while (noStopRequested) {
93:             try {
94:                 Thread.sleep(100);   // 10 frames per second
95:                
96:                 // increment the slide pointer
97:                 currSlide = (currSlide + 1) % slide.length;
98:
99:                 // signal the event thread to call paint()
100:                 repaint();
101:             } catch (InterruptedException x) {
102:                 Thread.currentThread().interrupt();
103:             }
104:         }
105:     }
106:
107:     public void stopRequest() {
108:         noStopRequested = false;
109:         internalThread.interrupt();
110:     }
111:
112:     public boolean isAlive() {
113:         return internalThread.isAlive();
114:     }
115:
116:     public static void main(String[] args) {
117:         SlideShow ss = new SlideShow();
118:
119:         JPanel p = new JPanel(new FlowLayout());
120:         p.add(ss);
121:
122:         JFrame f = new JFrame(SlideShow Demo);
123:         f.setContentPane(p);
124:         f.setSize(250, 150);
125:         f.setVisible(true);
126:     }
127: }
In main() (lines 116126), a new SlideShow instance is constructed (line 117) and put into a JPanel with a FlowLayout to let the instance of SlideShow take on its preferred size (lines 119120). This JPanel is put into a JFrame and set visible.
Inside the constructor (lines 1337), currSlide is set to initially be . currSlide is the index into the BufferedImage[] referred to by slide indicating the current slide to display. Because currSlide is set by one thread (the internal thread) and read by another in paint() (the event thread), it must be volatile to ensure that the event thread sees the changes in value (line 8). The buildSlides() method is called to create the set of images used for the animation. The rest of the constructor sets the dimensions of the component and starts up the internal thread.
The buildSlides() method (lines 3985) is used to construct an array of 20 images (line 50) to loop through. High-quality rendering hints are used because the images are drawn on only once and are displayed over and over (lines 4248, 62). Each of the images is constructed and drawn on in the for loop (lines 5584). First, a blue rectangle is filled in (lines 52, 6465). Then a yellow circle of varying diameter is drawn in the center (lines 53, 6777). The last shape drawn onto each image is a black rectangle to outline the slide (lines 7981). Each graphics context is disposed of immediately when it is no longer needed (line 83).
Whenever the paint() method  (lines 8789) is called by the event thread, the current slide is drawn onto the component. Because currSlide is volatile , the event thread always sees the most recent index value.
The internal thread invokes the runWork() method (lines 91105). Inside, it continues to execute the while loop until another thread comes along and invokes stopRequest() . Each time through, the internal thread sleeps for 0.1 seconds, increments the frame number, and requests that the event thread repaint the component as soon as possible (lines 94100). The slide indexed by currSlide is kept in the range to (slide.length - 1) (line 97). The internal thread loops through all of the slides over and over until stopRequest() is called.
Figure 9.10 catches SlideShow just as the yellow circle is beginning to expand. Figure 9.11 shows it when the yellow circle has expanded almost enough to touch the edges of the component. Figure 9.12 shows it when the yellow circle has grown to almost big enough to eclipse the entire blue region. After the yellow circle has grown to fill the component, it begins to shrink until it is a tiny circle again. This animation loop continues until stopRequest() is called. In this example I used simple drawing to keep the code size down, but you can feel free to use images of any complexity in this animation component.
Figure 9.10: SlideShow when the yellow circle is just beginning to expand.
Figure 9.11: SlideShow when the yellow circle has almost expanded to the edges.
Figure 9.12: SlideShow when the yellow circle has almost engulfed the whole component.

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