Multithreaded Graphics and Double Buffering #Programming Code Examples #Java/J2EE/J2ME #Java Threads

ShipSimulation.java  Illustrates the basic approach of multithreaded graphics whereas a thread adjusts parameters affecting the appearance of the graphics and then calls repaint to schedule an update of the display. 

import java.applet.Applet;
import java.awt.*;

public class ShipSimulation extends Applet implements Runnable {
  ...
  
  public void run() {
    Ship s;
    for(int i=0; i<ships .length; i++) {
      s = ships[i];
      s.move(); // Update location.
    }
    repaint();
  }

  ...
  
  public void paint(Graphics g) {
    Ship s;
    for(int i=0; i<ships.length; i++) {
      s = ships[i];
      g.draw(s); // Draw at current location.
    }
  }
}
*************************
DrawCircles.java An applet that draws a circle where the user clicks the mouse.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

/** An applet that draws a small circle where you click.
 
public class DrawCircles extends Applet {

  private Vector circles;

  /** When you click the mouse, create a SimpleCircle,
   *  put it in the Vector, and tell the system
   *  to repaint (which calls update, which clears
   *  the screen and calls paint).
   */

  private class CircleDrawer extends MouseAdapter {
    public void mousePressed(MouseEvent event) {
      circles.addElement(
         new SimpleCircle(event.getX(),event.getY(),25));
      repaint();
    }
  }

  public void init() {
    circles = new Vector();
    addMouseListener(new CircleDrawer());
    setBackground(Color.white);
  }

  /** This loops down the available SimpleCircle objects,
   *  drawing each one.
   */

  public void paint(Graphics g) {
    SimpleCircle circle;
    for(int i=0; i<circles.size(); i++) {
      circle = (SimpleCircle)circles.elementAt(i);
      circle.draw(g);
    }
  }
}
******************************
SimpleCircle.java A class to store the x, y, and radius of a circle. Also, provides a draw method to paint the circle on the graphics object.
import java.awt.*;

/** A class to store an x, y, and radius, plus a draw method.
 //
public class SimpleCircle {
  private int x, y, radius;

  public SimpleCircle(int x, int y, int radius) {
    setX(x);
    setY(y);
    setRadius(radius);
  }

  /** Given a Graphics, draw the SimpleCircle
   *  centered around its current position.
   */

  public void draw(Graphics g) {
    g.fillOval(x - radius, y - radius,
               radius * 2, radius * 2);
  }

  public int getX() { return(x); }

  public void setX(int x) { this.x = x; }

  public int getY() { return(y); }

  public void setY(int y) { this.y = y; }

  public int getRadius() { return(radius); }

  public void setRadius(int radius) {
    this.radius = radius;
  }
}
//
Rubberband.java  Draws a rectangle where one corner is fixed (initial selection of the mouse) and the opposite corner is determined by the location of the dragged mouse. Illustrates drawing directly into the graphics object instead of performing the drawing in the paint method. The graphics object is obtained by calling getGraphics.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

/** Draw "rubberband" rectangles when the user drags
 *  the mouse.
 *
  */

public class Rubberband extends Applet {
  private int startX, startY, lastX, lastY;

  public void init() {
    addMouseListener(new RectRecorder());
    addMouseMotionListener(new RectDrawer());
    setBackground(Color.white);
  }

  /** Draw the rectangle, adjusting the x, y, w, h
   *  to correctly accommodate for the opposite corner of the
   *  rubberband box relative to the start position.
   */

  private void drawRectangle(Graphics g, int startX, int startY,
                             int stopX, int stopY ) {
    int x, y, w, h;
    x = Math.min(startX, stopX);
    y = Math.min(startY, stopY);
    w = Math.abs(startX - stopX);
    h = Math.abs(startY - stopY);
    g.drawRect(x, y, w, h);
  }

  private class RectRecorder extends MouseAdapter {

    /** When the user presses the mouse, record the
     *  location of the top-left corner of rectangle.
     */

    public void mousePressed(MouseEvent event) {
      startX = event.getX();
      startY = event.getY();
      lastX = startX;
      lastY = startY;
    }

    /** Erase the last rectangle when the user releases
     *  the mouse.
     */

    public void mouseReleased(MouseEvent event) {
      Graphics g = getGraphics();
      g.setXORMode(Color.lightGray);
      drawRectangle(g, startX, startY, lastX, lastY);
    }
  } 

  private class RectDrawer extends MouseMotionAdapter {

    /** This draws a rubberband rectangle, from the location
     *  where the mouse was first clicked to the location
     *  where the mouse is dragged.
     */

    public void mouseDragged(MouseEvent event) {
      int x = event.getX();
      int y = event.getY();

      Graphics g = getGraphics();
      g.setXORMode(Color.lightGray);
      drawRectangle(g, startX, startY, lastX, lastY);
      drawRectangle(g, startX, startY, x, y);

      lastX = x;
      lastY = y;
    }
  } 
}
*//
Bounce.java An applet that contains moving circles that bounce off the walls. Illustrates overriding update to reduce animation flickering and performing incremental updating in the paint method. Here, to achieve animation, a single thread continuously calls repaint while subsequently sleeping for a 100 milliseconds
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

/** Bounce circles around on the screen. Doesn't use double
 *  buffering, so has problems with overlapping circles.
 *  Overrides update to avoid flicker problems.
 *
 */

public class Bounce extends Applet implements Runnable,
                                              ActionListener {
  private Vector circles;
  private int width, height;
  private Button startButton, stopButton;
  private Thread animationThread = null;

  public void init() {
    setBackground(Color.white);
    width = getSize().width;
    height = getSize().height;
    circles = new Vector();
    startButton = new Button("Start a circle");
    startButton.addActionListener(this);
    add(startButton);
    stopButton = new Button("Stop all circles");
    stopButton.addActionListener(this);
    add(stopButton);
  }

  /** When the "start" button is pressed, start the animation
   *  thread if it is not already started. Either way, add a
   *  circle to the Vector of circles that are being bounced.
   *  

* When the "stop" button is pressed, stop the thread and * clear the Vector of circles. */ public void actionPerformed(ActionEvent event) { if (event.getSource() == startButton) { if (circles.size() == 0) { // Erase any circles from previous run. getGraphics().clearRect(0, 0, getSize().width, getSize().height); animationThread = new Thread(this); animationThread.start(); } int radius = 25; int x = radius + randomInt(width - 2 * radius); int y = radius + randomInt(height - 2 * radius); int deltaX = 1 + randomInt(10); int deltaY = 1 + randomInt(10); circles.addElement(new MovingCircle(x, y, radius, deltaX, deltaY)); } else if (event.getSource() == stopButton) { if (animationThread != null) { animationThread = null; circles.removeAllElements(); } } repaint(); } /** Each time around the loop, call paint and then take a * short pause. The paint method will move the circles and * draw them. */ public void run() { Thread myThread = Thread.currentThread(); // Really while animationThread not null while(animationThread==myThread) { repaint(); pause(100); } } /** Skip the usual screen-clearing step of update so that * there is no flicker between each drawing step. */ public void update(Graphics g) { paint(g); } /** Erase each circle's old position, move it, then draw it * in new location. */ public void paint(Graphics g) { MovingCircle circle; for(int i=0; i<circles .size(); i++) { circle = (MovingCircle)circles.elementAt(i); g.setColor(getBackground()); circle.draw(g); // Old position. circle.move(width, height); g.setColor(getForeground()); circle.draw(g); // New position. } } // Returns an int from 0 to max (inclusive), // yielding max + 1 possible values. private int randomInt(int max) { double x = Math.floor((double)(max + 1) * Math.random()); return((int)(Math.round(x))); } // Sleep for the specified amount of time. private void pause(int milliseconds) { try { Thread.sleep((long)milliseconds); } catch(InterruptedException ie) {} } } *// MovingCircle.java An extension of SimpleCircle that can be moved about and bounces off walls. /** An extension of SimpleCircle that can be moved around * according to deltaX and deltaY values. Movement will * continue in a given direction until the edge of the circle * reaches a wall, when it will "bounce" and move in the other * direction. * */ public class MovingCircle extends SimpleCircle { private int deltaX, deltaY; public MovingCircle(int x, int y, int radius, int deltaX, int deltaY) { super(x, y, radius); this.deltaX = deltaX; this.deltaY = deltaY; } public void move(int windowWidth, int windowHeight) { setX(getX() + getDeltaX()); setY(getY() + getDeltaY()); bounce(windowWidth, windowHeight); } private void bounce(int windowWidth, int windowHeight) { int x = getX(), y = getY(), radius = getRadius(), deltaX = getDeltaX(), deltaY = getDeltaY(); if ((x - radius < 0) && (deltaX windowWidth) && (deltaX > 0)) { setDeltaX(-deltaX); } if ((y -radius < 0) && (deltaY windowHeight) && (deltaY > 0)) { setDeltaY(-deltaY); } } public int getDeltaX() { return(deltaX); } public void setDeltaX(int deltaX) { this.deltaX = deltaX; } public int getDeltaY() { return(deltaY); } public void setDeltaY(int deltaY) { this.deltaY = deltaY; } } *// SimpleCircle.java A class to store the x, y, and radius of a circle. Also, provides a draw method to paint the circle on the graphics object. import java.awt.*; /** A class to store an x, y, and radius, plus a draw method. * */ public class SimpleCircle { private int x, y, radius; public SimpleCircle(int x, int y, int radius) { setX(x); setY(y); setRadius(radius); } /** Given a Graphics, draw the SimpleCircle * centered around its current position. */ public void draw(Graphics g) { g.fillOval(x - radius, y - radius, radius * 2, radius * 2); } public int getX() { return(x); } public void setX(int x) { this.x = x; } public int getY() { return(y); } public void setY(int y) { this.y = y; } public int getRadius() { return(radius); } public void setRadius(int radius) { this.radius = radius; } } *// DoubleBufferBounce.java An enhancement to the previous applet containing bouncing circles. In this case, double buffering is used to improve the animation; all incremental updating is done in an off-screen image and then the image is drawn to the screen. import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.util.Vector; /** Bounce circles around on the screen, using double buffering * for speed and to avoid problems with overlapping circles. * Overrides update to avoid flicker problems. * */ public class DoubleBufferBounce extends Applet implements Runnable, ActionListener { private Vector circles; private int width, height; private Image offScreenImage; private Graphics offScreenGraphics; private Button startButton, stopButton; private Thread animationThread = null; public void init() { setBackground(Color.white); width = getSize().width; height = getSize().height; offScreenImage = createImage(width, height); offScreenGraphics = offScreenImage.getGraphics(); // Automatic in some systems, not in others. offScreenGraphics.setColor(Color.black); circles = new Vector(); startButton = new Button("Start a circle"); startButton.addActionListener(this); add(startButton); stopButton = new Button("Stop all circles"); stopButton.addActionListener(this); add(stopButton); } /** When the "start" button is pressed, start the animation * thread if it is not already started. Either way, add a * circle to the Vector of circles that are being bounced. *

* When the "stop" button is pressed, stop the thread and * clear the Vector of circles. */ public void actionPerformed(ActionEvent event) { if (event.getSource() == startButton) { if (circles.size() == 0) { animationThread = new Thread(this); animationThread.start(); } int radius = 25; int x = radius + randomInt(width - 2 * radius); int y = radius + randomInt(height - 2 * radius); int deltaX = 1 + randomInt(10); int deltaY = 1 + randomInt(10); circles.addElement(new MovingCircle(x, y, radius, deltaX, deltaY)); repaint(); } else if (event.getSource() == stopButton) { if (animationThread != null) { animationThread = null; circles.removeAllElements(); } } } /** Each time around the loop, move each circle based on its * current position and deltaX/deltaY values. These values * reverse when the circles reach the edge of the window. */ public void run() { MovingCircle circle; Thread myThread = Thread.currentThread(); // Really while animationThread not null. while(animationThread==myThread) { for(int j=0; j<circles .size(); j++) { circle = (MovingCircle)circles.elementAt(j); circle.move(width, height); } repaint(); pause(100); } } /** Skip the usual screen-clearing step of update so that * there is no flicker between each drawing step. */ public void update(Graphics g) { paint(g); } /** Clear the off-screen pixmap, draw each circle onto it, then * draw that pixmap onto the applet window. */ public void paint(Graphics g) { offScreenGraphics.clearRect(0, 0, width, height); MovingCircle circle; for(int i=0; i<circles.size(); i++) { circle = (MovingCircle)circles.elementAt(i); circle.draw(offScreenGraphics); } g.drawImage(offScreenImage, 0, 0, this); } // Returns an int from 0 to max (inclusive), yielding max + 1 // possible values. private int randomInt(int max) { double x = Math.floor((double)(max + 1) * Math.random()); return((int)(Math.round(x))); } // Sleep for the specified amount of time. private void pause(int milliseconds) { try { Thread.sleep((long)milliseconds); } catch(InterruptedException ie) {} } } **// ImageAnimation.java Illustrates animation of images by using a thread to cycle through an array of images. See ImageAnimation.html. Uses the following class and images: import java.applet.Applet; import java.awt.*; public class ImageAnimation extends Applet { /** Sequence through an array of 15 images to perform the * animation. A separate Thread controls each tumbling Duke. * The Applet's stop method calls a public service of the * Duke class to terminate the thread. Override update to * avoid flicker problems. * */ private static final int NUMDUKES = 2; private Duke[] dukes; private int i; public void init() { dukes = new Duke[NUMDUKES]; setBackground(Color.white); } /** Start each thread, specifing a direction to sequence * through the array of images. */ public void start() { int tumbleDirection; for (int i=0; i<NUMDUKES ; i++) { tumbleDirection = (i%2==0) ? 1 :-1; dukes[i] = new Duke(tumbleDirection, this); dukes[i].start(); } } /** Skip the usual screen-clearing step of update so that * there is no flicker between each drawing step. */ public void update(Graphics g) { paint(g); } public void paint(Graphics g) { for (i=0 ; i<NUMDUKES ; i++) { if (dukes[i] != null) { g.drawImage(Duke.images[dukes[i].getIndex()], 200*i, 0, this); } } } /** When the Applet's stop method is called, use the public * service, setState, of the Duke class to set a flag and * terminate the run method of the thread. */ public void stop() { for (int i=0; i<NUMDUKES ; i++) { if (dukes[i] != null) { dukes[i].setState(Duke.STOP); } } } } *// Duke.java A subclass of Thread holding the images for the animation. import java.applet.Applet; import java.awt.*; /** Duke is a Thread that has knowledge of the parent applet * (highly coupled) and thus can call the parent's repaint * method. Duke is mainly responsible for changing an index * value into an image array. * */ public class Duke extends Thread { public static final int STOP = 0; public static final int RUN = 1; public static final int WAIT = 2; public static Image[] images; private static final int NUMIMAGES = 15; private static Object lock = new Object(); private int state = RUN; private int tumbleDirection; private int index = 0; private Applet parent; public Duke(int tumbleDirection, Applet parent) { this.tumbleDirection = tumbleDirection; this.parent = parent; synchronized(lock) { if (images==null) { // If not previously loaded. images = new Image[ NUMIMAGES ]; for (int i=0; i<NUMIMAGES; i++) { images[i] = parent.getImage( parent.getCodeBase(), "images/T" + i + ".gif"); } } } } /** Return current index into image array. */ public int getIndex() { return index; } /** Public method to permit setting a flag to stop or * suspend the thread. State is monitored through * corresponding checkState method. */ public synchronized void setState(int state) { this.state = state; if (state==RUN) { notify(); } } /** Returns the desired state (RUN, STOP, WAIT) of the * thread. If the thread is to be suspended, then the * thread method wait is continuously called until the * state is changed through the public method setState. */ private synchronized int checkState() { while (state==WAIT) { try { wait(); } catch (InterruptedException e) {} } return state; } /** The variable index (into image array) is incremented * once each time through the while loop, calls repaint, * and pauses for a moment. Each time through the loop the * state (flag) of the thread is checked. */ public void run() { while (checkState()!=STOP) { index += tumbleDirection; if (index = NUMIMAGES) { index = 0; } parent.repaint(); try { Thread.sleep(100); } catch (InterruptedException e) { break; // Break while loop. } } } } *// TimedAnimation.java An applet that demonstrates animation of an image by using a Timer. Note that Timer is located in the javax.swing package. import java.awt.*; import javax.swing.*; /** An example of performing animation through Swing timers. * Two timed Dukes are created with different timer periods. * */ public class TimedAnimation extends JApplet { private static final int NUMDUKES = 2; private TimedDuke[] dukes; private int i, index; public void init() { dukes = new TimedDuke[NUMDUKES]; setBackground(Color.white); dukes[0] = new TimedDuke( 1, 100, this); dukes[1] = new TimedDuke(-1, 500, this); } // Start each Duke timer. public void start() { for (int i=0; i<numdukes ; i++) { dukes[i].startTimer(); } } public void paint(Graphics g) { for (i=0 ; i<NUMDUKES ; i++) { if (dukes[i] != null) { index = dukes[i].getIndex(); g.drawImage(TimedDuke.images[index], 200*i, 0, this); } } } // Stop each Duke timer. public void stop() { for (int i=0; i<NUMDUKES ; i++) { dukes[i].stopTimer(); } } } **// TimedDuke.java Facilitates animation of Duke images by creating an internal timer. import java.applet.Applet; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** Duke facilitates animation by creating an internal timer. * When the timer fires, an actionPerformed event is * triggered, which in turn calls repaint on the parent * Applet. * */ public class TimedDuke implements ActionListener { private static final int NUMIMAGES = 15; private static boolean loaded = false; private static Object lock = new Object(); private int tumbleDirection; private int msec; private int index = 0; private Applet parent; private Timer timer; public static Image[] images = new Image[NUMIMAGES]; public TimedDuke(int tumbleDirection, int msec, Applet parent) { this.tumbleDirection = tumbleDirection; this.msec = msec; this.parent = parent; synchronized (lock) { if (!loaded) { MediaTracker tracker = new MediaTracker(parent); for (int i=0; i<NUMIMAGES; i++) { images[i] = parent.getImage(parent.getCodeBase(), "images/T" + i + ".gif"); tracker.addImage(images[i],0); } try { tracker.waitForAll(); } catch (InterruptedException ie) {} if (!tracker.isErrorAny()) { loaded = true; } } } timer = new Timer(msec, this); } // Return current index into image array. public int getIndex() { return index; } // Receives timer firing event. Increments the index into // image array and forces repainting of the new image. public void actionPerformed(ActionEvent event) { index += tumbleDirection; if (index = NUMIMAGES) { index = 0; } parent.repaint(); } // Public service to start the timer. public void startTimer() { timer.start(); } // Public service to stop the timer. public void stopTimer() { timer.stop(); } } **//

Note: Brought from our old site: http://www.salearningschool.com/example_codes/ on Jan 2nd, 2017 From: http://sitestree.com/?p=10298
Categories:Programming Code Examples, Java/J2EE/J2ME, Java Threads
Tags:Java/J2EE/J2MEJava Threads
Post Data:2017-01-02 16:04:31

Shop Online: https://www.ShopForSoul.com/
(Big Data, Cloud, Security, Machine Learning): Courses: http://Training.SitesTree.com
In Bengali: http://Bangla.SaLearningSchool.com
http://SitesTree.com
8112223 Canada Inc./JustEtc: http://JustEtc.net (Software/Web/Mobile/Big-Data/Machine Learning)
Shop Online: https://www.ShopForSoul.com/
Medium: https://medium.com/@SayedAhmedCanada