1 // CPS616 Assignment 2 2 // Mehmet SEN 3 // Using threads to construct a applet, in which dynamically sizing 4 // bubbles are moving. 5 // HOW TO USE THREADS? 6 // 1. Add the words "implements Runnable" to the applet class 7 // 2. Define an instance variable to hold the applet's thread 8 // 3. Modify start() method to spawn a thread and start it running. 9 // 4. Create a run() method that contains the actual code that starts 10 // your applet running 11 // 12 // In the following program Bubble class constructs a thread and 13 // BubblesApplet class creates an array of independent threads using the 14 // Bubble class. You can watch all four steps by looking at the Bubble 15 // class to create an independent thread 16 17 import java.awt.*; 18 import java.lang.Math; 19 import java.util.Random; 20 21 public class BubblesApplet extends java.applet.Applet { 22 23 public int W = 400; 24 public int H = 300; 25 public int N = 15; 26 public final int minSize = 10; 27 public final int maxSize = 50; 28 public final int minNaptime = 1; 29 public final int maxNaptime = 500; 30 public final Color colors[] = { 31 Color.red, 32 Color.pink, 33 Color.orange, 34 Color.yellow, 35 Color.green, 36 Color.magenta, 37 Color.blue, 38 Color.cyan, 39 Color.white, 40 Color.gray, 41 Color.lightGray, 42 Color.darkGray 43 }; 44 public final Color bg = Color.black; 45 boolean threadSuspended = false; 46 Image im; 47 Graphics offscreen; 48 Random rand; 49 Bubble bubbles[] = new Bubble[N]; 50 51 public void init() { 52 Rectangle r=bounds(); 53 W = r.width; 54 H = r.height; 55 resize(W, H); 56 rand = new Random((long)System.currentTimeMillis()); 57 try { 58 im = createImage(W, H); 59 offscreen = im.getGraphics(); 60 } catch (Exception e) { 61 offscreen = null; 62 } 63 } 64 65 /* 66 Create each bubble with some random parameters and start its thread 67 */ 68 69 public void start() { 70 for (int i=0; i<N; i++) { 71 if (bubbles[i] == null) { 72 bubbles[i] = new Bubble(this, 73 (int)((double)W*rand.nextDouble()), 74 (int)((double)H*rand.nextDouble()), 75 minSize + (int)((double)(maxSize-minSize)*rand.nextDouble()), 76 minNaptime + (int)((double)(maxNaptime-minNaptime)*rand.nextDouble()), 77 colors[(int)((double)colors.length*rand.nextDouble())], 78 bg, bounds()); 79 bubbles[i].start(); 80 } 81 } 82 repaint(); 83 } 84 85 /* when applet is stopped, stop individual threads */ 86 public void stop() { 87 for (int i=0; i<N; i++) { 88 bubbles[i].stop(); 89 } 90 } 91 92 /* override the update method to reduce flashing */ 93 public void update(Graphics g) { 94 paint(g); 95 } 96 97 /* we are using double buffering to reduce flashing */ 98 public void paint(Graphics g) { 99 if (offscreen != null) { 100 paintApplet(offscreen); 101 g.drawImage(im, 0, 0, this); 102 } else { 103 paintApplet(g); 104 } 105 } 106 107 /* call each bubble's paint method */ 108 public void paintApplet(Graphics g) { 109 boolean changed = false; 110 g.setColor(bg); 111 g.fillRect(0, 0, W, H); 112 for (int i=0; i<N; i++) { 113 bubbles[i].paint(g); 114 } 115 } 116 117 } // end BubblesApplet class 118 119 /** 120 This class implements a Bubble. Each bubble will call its applet's paint method 121 asynchronously when it is time for growth or decay. 122 */ 123 124 class Bubble implements Runnable { 125 126 static int threadNum = 1; 127 private Color color = null; 128 private Color bg = Color.black; 129 private int naptime = 500; 130 private int size = 50; 131 private int growthFactor = 1; 132 private int ox = 0; /* location within applet's frame of reference */ 133 private int oy = 0; /* center of the bubble */ 134 private int dx=2; 135 private int dy=2; 136 private Rectangle rect; 137 private Graphics graphics; 138 private int current; 139 private int previous; 140 private boolean growing = false; 141 142 public Thread thread = null; 143 public boolean changed = true; 144 145 BubblesApplet applet; 146 147 public Bubble(BubblesApplet applet, int x, int y, int s, int n, Color c, Color bg, Rectangle r) { 148 this.applet = applet; 149 ox = x; 150 oy = y; 151 size = s; 152 naptime = n; 153 color = c; 154 rect = r; 155 dx = (Math.random()>.5)?-2:2; 156 dy = (Math.random()>.5)?-2:2; 157 158 if (color == null) { 159 color = Color.black; 160 } 161 current = previous = s; 162 } 163 164 /* main thread run method */ 165 public void run() { 166 thread.setPriority(Thread.MIN_PRIORITY+1); 167 while (thread != null) { 168 changed = true; 169 previous = current; 170 if (growing) { 171 current += growthFactor; 172 } else { 173 current -= growthFactor; 174 } 175 if (current == size || current == 0) { 176 growing = !growing; 177 } 178 try { thread.sleep(naptime); } 179 catch (InterruptedException e) {}; 180 applet.repaint(); 181 } 182 thread = null; 183 } 184 185 /* Here , thread is started */ 186 public void start() { 187 if (thread == null) { 188 thread = new Thread(this, Integer.toString(threadNum++)); 189 thread.start(); 190 } 191 } 192 193 public void stop() { 194 thread = null; 195 } 196 197 /* Erase last position and paint the new one */ 198 public void paint(Graphics g) { 199 int prevHalf = (int)(previous/2); 200 int curHalf = (int)(current/2); 201 202 g.setColor(bg); 203 g.fillOval(ox-prevHalf, oy-prevHalf, previous, previous); 204 205 checkboundary(); 206 ox += dx; 207 oy += dy; 208 g.setColor(color); 209 g.fillOval(ox-curHalf, oy-curHalf, current, current); 210 } 211 212 public void checkboundary() { 213 int curHalf = (int)(current/2); 214 int nx = ox+dx; /* caculate new location */ 215 int ny = oy+dy; 216 217 /* check if new location out of boundary */ 218 if ( (nx < curHalf) || (nx+current >= rect.width+curHalf) ) dx = -dx; 219 if ( (ny < curHalf) || (ny+current >= rect.height+curHalf) ) dy = -dy; 220 // System.out.println("nx:"+nx+ " ny:"+ny + "cur:"+current+ " dy:"+dy +"rect.y "+rect.y+ " rect.height "+ rect.height+"rect.x "+rect.x+ " rect.width "+ rect.width); 221 } 222 223 } // end Bubble class 224 225 226 227 228