001 package com.croftsoft.core.animation; 002 003 import java.awt.EventQueue; 004 import java.awt.Graphics; 005 import java.awt.Graphics2D; 006 import java.awt.Rectangle; 007 import java.lang.reflect.InvocationTargetException; 008 import javax.swing.JComponent; 009 010 import com.croftsoft.core.animation.factory.DefaultAnimationFactory; 011 import com.croftsoft.core.lang.NullArgumentException; 012 import com.croftsoft.core.lang.lifecycle.Lifecycle; 013 import com.croftsoft.core.util.loop.LoopGovernor; 014 015 /********************************************************************* 016 * Animated Swing component. 017 * 018 * @version 019 * $Id: AnimatedComponent.java,v 1.3 2008/09/28 21:49:39 croft Exp $ 020 * @since 021 * 2002-03-10 022 * @author 023 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 024 *********************************************************************/ 025 026 public class AnimatedComponent 027 extends JComponent 028 implements Lifecycle 029 ////////////////////////////////////////////////////////////////////// 030 ////////////////////////////////////////////////////////////////////// 031 { 032 033 private static final long serialVersionUID = 0L; 034 035 public static final String ANIMATION_THREAD_NAME = "Animation"; 036 037 // 038 039 protected final Runnable animationRunner; 040 041 // 042 043 protected ComponentAnimator componentAnimator; 044 045 protected RepaintCollector repaintCollector; 046 047 protected LoopGovernor loopGovernor; 048 049 protected Thread animationThread; 050 051 protected boolean stopRequested; 052 053 ////////////////////////////////////////////////////////////////////// 054 // constructor methods 055 ////////////////////////////////////////////////////////////////////// 056 057 /********************************************************************* 058 * Main constructor. 059 *********************************************************************/ 060 public AnimatedComponent ( 061 ComponentAnimator componentAnimator, 062 RepaintCollector repaintCollector, 063 LoopGovernor loopGovernor ) 064 ////////////////////////////////////////////////////////////////////// 065 { 066 setComponentAnimator ( componentAnimator ); 067 068 setRepaintCollector ( repaintCollector ); 069 070 setLoopGovernor ( loopGovernor ); 071 072 setOpaque ( true ); 073 074 animationRunner = 075 new Runnable ( ) 076 { 077 public void run ( ) 078 { 079 animate ( ); 080 } 081 }; 082 } 083 084 /********************************************************************* 085 * Convenience constructor. 086 * 087 * @param frequency 088 * 089 * The targeted update frequency in loops per second. 090 *********************************************************************/ 091 public AnimatedComponent ( 092 ComponentAnimator componentAnimator, 093 AnimationFactory animationFactory, 094 double frequency ) 095 ////////////////////////////////////////////////////////////////////// 096 { 097 this ( 098 componentAnimator, 099 animationFactory.createRepaintCollector ( ), 100 animationFactory.createLoopGovernor ( frequency ) ); 101 } 102 103 /********************************************************************* 104 * Convenience constructor. 105 *********************************************************************/ 106 public AnimatedComponent ( 107 ComponentAnimator componentAnimator, 108 AnimationFactory animationFactory ) 109 ////////////////////////////////////////////////////////////////////// 110 { 111 this ( 112 componentAnimator, 113 animationFactory.createRepaintCollector ( ), 114 animationFactory.createLoopGovernor ( ) ); 115 } 116 117 /********************************************************************* 118 * Convenience constructor. 119 * 120 * @param frequency 121 * 122 * The targeted update frequency in loops per second. 123 *********************************************************************/ 124 public AnimatedComponent ( 125 ComponentAnimator componentAnimator, 126 double frequency ) 127 ////////////////////////////////////////////////////////////////////// 128 { 129 this ( 130 componentAnimator, 131 DefaultAnimationFactory.INSTANCE, 132 frequency ); 133 } 134 135 /********************************************************************* 136 * Convenience constructor. 137 *********************************************************************/ 138 public AnimatedComponent ( ComponentAnimator componentAnimator ) 139 ////////////////////////////////////////////////////////////////////// 140 { 141 this ( 142 componentAnimator, 143 DefaultAnimationFactory.INSTANCE ); 144 } 145 146 ////////////////////////////////////////////////////////////////////// 147 // mutator methods 148 ////////////////////////////////////////////////////////////////////// 149 150 public synchronized ComponentAnimator setComponentAnimator ( 151 ComponentAnimator componentAnimator ) 152 ////////////////////////////////////////////////////////////////////// 153 { 154 NullArgumentException.check ( componentAnimator ); 155 156 ComponentAnimator oldComponentAnimator = this.componentAnimator; 157 158 this.componentAnimator = componentAnimator; 159 160 return oldComponentAnimator; 161 } 162 163 public synchronized RepaintCollector setRepaintCollector ( 164 RepaintCollector repaintCollector ) 165 ////////////////////////////////////////////////////////////////////// 166 { 167 NullArgumentException.check ( repaintCollector ); 168 169 RepaintCollector oldRepaintCollector = this.repaintCollector; 170 171 this.repaintCollector = repaintCollector; 172 173 return oldRepaintCollector; 174 } 175 176 public synchronized LoopGovernor setLoopGovernor ( 177 LoopGovernor loopGovernor ) 178 ////////////////////////////////////////////////////////////////////// 179 { 180 NullArgumentException.check ( loopGovernor ); 181 182 LoopGovernor oldLoopGovernor = this.loopGovernor; 183 184 this.loopGovernor = loopGovernor; 185 186 return oldLoopGovernor; 187 } 188 189 ////////////////////////////////////////////////////////////////////// 190 // interface Lifecycle methods 191 ////////////////////////////////////////////////////////////////////// 192 193 public void init ( ) 194 ////////////////////////////////////////////////////////////////////// 195 { 196 // empty 197 } 198 199 public synchronized void start ( ) 200 ////////////////////////////////////////////////////////////////////// 201 { 202 stopRequested = false; 203 204 if ( animationThread == null ) 205 { 206 animationThread = new Thread ( 207 new Runnable ( ) 208 { 209 public void run ( ) 210 { 211 loop ( ); 212 } 213 }, 214 ANIMATION_THREAD_NAME ); 215 216 animationThread.setPriority ( Thread.MIN_PRIORITY ); 217 218 animationThread.setDaemon ( true ); 219 220 animationThread.start ( ); 221 } 222 else 223 { 224 notify ( ); 225 } 226 } 227 228 public synchronized void stop ( ) 229 ////////////////////////////////////////////////////////////////////// 230 { 231 stopRequested = true; 232 233 animationThread.interrupt ( ); 234 } 235 236 public synchronized void destroy ( ) 237 ////////////////////////////////////////////////////////////////////// 238 { 239 animationThread = null; 240 241 stopRequested = false; 242 243 notify ( ); 244 } 245 246 ////////////////////////////////////////////////////////////////////// 247 // overridden JComponent methods 248 ////////////////////////////////////////////////////////////////////// 249 250 @Override 251 public void paintComponent ( Graphics graphics ) 252 ////////////////////////////////////////////////////////////////////// 253 { 254 componentAnimator.paint ( this, ( Graphics2D ) graphics ); 255 } 256 257 @Override 258 public void repaint ( ) 259 ////////////////////////////////////////////////////////////////////// 260 { 261 repaintCollector.repaint ( ); 262 } 263 264 @Override 265 public void repaint ( long tm ) 266 ////////////////////////////////////////////////////////////////////// 267 { 268 repaintCollector.repaint ( ); 269 } 270 271 @Override 272 public void repaint ( 273 int x, 274 int y, 275 int width, 276 int height ) 277 ////////////////////////////////////////////////////////////////////// 278 { 279 repaintCollector.repaint ( x, y, width, height ); 280 } 281 282 @Override 283 public void repaint ( 284 long tm, 285 int x, 286 int y, 287 int width, 288 int height ) 289 ////////////////////////////////////////////////////////////////////// 290 { 291 repaintCollector.repaint ( x, y, width, height ); 292 } 293 294 @Override 295 public void repaint ( Rectangle r ) 296 ////////////////////////////////////////////////////////////////////// 297 { 298 repaintCollector.repaint ( r.x, r.y, r.width, r.height ); 299 } 300 301 ////////////////////////////////////////////////////////////////////// 302 // protected methods 303 ////////////////////////////////////////////////////////////////////// 304 305 protected void loop ( ) 306 ////////////////////////////////////////////////////////////////////// 307 { 308 while ( animationThread != null ) 309 { 310 try 311 { 312 EventQueue.invokeAndWait ( animationRunner ); 313 314 loopGovernor.govern ( ); 315 316 if ( stopRequested ) 317 { 318 synchronized ( this ) 319 { 320 while ( stopRequested ) 321 { 322 wait ( ); 323 } 324 } 325 } 326 } 327 catch ( InterruptedException ex ) 328 { 329 // ignore 330 } 331 catch ( InvocationTargetException ex ) 332 { 333 ex.getCause ( ).printStackTrace ( ); 334 } 335 } 336 } 337 338 protected void animate ( ) 339 ////////////////////////////////////////////////////////////////////// 340 { 341 componentAnimator.update ( this ); 342 343 int count = repaintCollector.getCount ( ); 344 345 Rectangle [ ] repaintRegions 346 = repaintCollector.getRepaintRegions ( ); 347 348 for ( int i = 0; i < count; i++ ) 349 { 350 paintImmediately ( repaintRegions [ i ] ); 351 } 352 353 repaintCollector.reset ( ); 354 } 355 356 ////////////////////////////////////////////////////////////////////// 357 ////////////////////////////////////////////////////////////////////// 358 }