title: Using a canvas object in a thread to do simple animations - Java
body: <p>I have an applet that, as written now, should be drawing and bouncing a ball around the top (<code>drawingpanel</code> in the code) after the "Run" button is pressed. Looking at other examples online and using code from a different program that did not use Canvas I am not able to figure out why my Ball object is not showing up. I have tested the flow of the program, and all the methods are being called as they should be, so it isn't the case where the code doesn't make it to the <code>paint</code> method. Any good resources on using Canvas/Thread would be great, or any advice on the following applet would be much appriciated. Thank you!</p>
  
  <pre><code>import java.awt.*;
  import java.applet.*;
  import java.awt.event.*;
  
  public class Bounce2 extends Applet implements ActionListener, AdjustmentListener, Runnable
  {
      private final static long serialVersionUID = 1L;
  
      //runtime variables
      boolean running = false;
      boolean currentlyCircle = true;
      boolean showtails = false;
      boolean kill = false;
  
      //buttons
      Button runbutton = new Button("Run"); 
      Button pausebutton = new Button("Pause");
      Button quitbutton = new Button("Quit");
  
      //text
      Label speedlabel = new Label("Speed");
      Label sizelabel = new Label("Size");
  
      //scrollbars
      private final int barHeight = 20;
      private final int SLIDER_WIDTH = 10;
      private final int MAXSPEED = 110;
      private final int MINSPEED = 0;
      private final int MAX_SIZE = 110;
      private final int MIN_SIZE = 10;
      Scrollbar speedbar = new Scrollbar(Scrollbar.HORIZONTAL, MAXSPEED/2, SLIDER_WIDTH, MINSPEED, MAXSPEED);
      Scrollbar sizebar = new Scrollbar(Scrollbar.HORIZONTAL, MAX_SIZE/2, SLIDER_WIDTH, MIN_SIZE, MAX_SIZE);
  
      //drawn objs
      Ball ball;
      Image buffer;
      int size = 50;  
      private Graphics obj;
      Point currentlocation = new Point(100,100);
      Point previouslocation;
      Point nextlocation;
  
      Rectangle circle;
      Rectangle screen;
      private Thread ballThread;
  
      //boundaries
      int bound_x;
      int bound_y;
  
      //directions
      int dx = 1; //1 = left, -1 = right
      int dy = 1; //1 = up, -1 = down
  
      //speed
      int speed = speedbar.getValue();
      int delay;
  
      //initialize the applet and draw everything
      public void init()
      {
          double colWeight[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//15 cols
          double rowWeight[] = {1,1,1,1,1,1,1,1,1,1}; //10 rows
          int colWidth[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//15 cols
          int rowHeight[] = {1,1,1,1,1,1,1,1,1,1}; //10 rows
          GridBagConstraints c = new GridBagConstraints();
          GridBagLayout gbl = new GridBagLayout();
          gbl.rowHeights = rowHeight;
          gbl.rowWeights = rowWeight;
          gbl.columnWeights = colWeight;
          gbl.columnWidths = colWidth;
          c.anchor = GridBagConstraints.CENTER;
  
          setBounds(0,0,480,640);
          setLayout(new BorderLayout());
          Panel controlpanel = new Panel();
          controlpanel.setLayout(gbl);
          controlpanel.setSize(640,80);
  
          Panel drawingpanel = new Panel(null);
          drawingpanel.setSize(640,400);
          ball = new Ball();
          drawingpanel.add("Center", ball);
          Rectangle circle = new Rectangle(size, size);
          Rectangle screen = new Rectangle(0,0,640,400);
          drawingpanel.setVisible(true);
  
          //speed scrollbar
          c.weightx = 1;
          c.weighty = 1;
          c.gridwidth = 3;
          c.gridheight = 1;
          c.gridx = 1;
          c.gridy = 7;
          c.fill= GridBagConstraints.HORIZONTAL;
          gbl.setConstraints(this.speedbar,c);
  
          //run button
          c.weightx = 1;
          c.weighty = 1;
          c.gridwidth = 2;
          c.gridheight = 1;
          c.gridx = 5;
          c.gridy = 7;
          c.fill= GridBagConstraints.HORIZONTAL;
          gbl.setConstraints(this.runbutton,c);
  
          //pause button
          c.weightx = 1;
          c.weighty = 1;
          c.gridwidth = 2;
          c.gridheight = 1;
          c.gridx = 8;
          c.gridy = 7;
          c.fill= GridBagConstraints.HORIZONTAL;
          gbl.setConstraints(this.pausebutton,c);
  
          //size scrollbar
          c.weightx = 1;
          c.weighty = 1;
          c.gridwidth = 3;
          c.gridheight = 1;
          c.gridx = 11;
          c.gridy = 7;
          c.fill= GridBagConstraints.HORIZONTAL;
          gbl.setConstraints(this.sizebar,c);
  
          //speed text label
          c.weightx = 1;
          c.weighty = 1;
          c.gridwidth = 3;
          c.gridheight = 1;
          c.gridx = 1;
          c.gridy = 8;
          c.fill= GridBagConstraints.HORIZONTAL;
          gbl.setConstraints(this.speedlabel,c);
  
          //size text label
          c.weightx = 1;
          c.weighty = 1;
          c.gridwidth = 3;
          c.gridheight = 1;
          c.gridx = 11;
          c.gridy = 8;
          c.fill= GridBagConstraints.HORIZONTAL;
          gbl.setConstraints(this.sizelabel,c);
  
          //quit button
          c.weightx = 1;
          c.weighty = 1;
          c.gridwidth = 3;
          c.gridheight = 1;
          c.gridx = 6;
          c.gridy = 9;
          c.fill= GridBagConstraints.HORIZONTAL;
          gbl.setConstraints(this.quitbutton,c);
  
          //add to the screen
          controlpanel.add(this.speedbar);
          controlpanel.add(this.runbutton);
          controlpanel.add(this.pausebutton);
          controlpanel.add(this.sizebar);
          controlpanel.add(this.speedlabel);
          controlpanel.add(this.sizelabel);
          controlpanel.add(this.quitbutton);
  
          //add listners
          speedbar.addAdjustmentListener(this);
          runbutton.addActionListener(this);
          pausebutton.addActionListener(this);
          sizebar.addAdjustmentListener(this);
          quitbutton.addActionListener(this);
  
          //add the panels
          add("South", controlpanel);
          add("Center", drawingpanel);
  
          //drawing paramaters, draw the first object
          System.err.println(obj);
          obj = drawingpanel.getGraphics();
          nextlocation = new Point(currentlocation.x+dx, currentlocation.y+dy);
  
          setVisible(true);
          validate();
      }
  
      public void start()
      {
          if (ballThread == null)
          {
              ballThread = new Thread(this);
              ballThread.start();
              repaint();
          }
      }
  
          public void run()
  {
      Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
      while (!kill)
      {
          if (running)
          {
              ball.move();
              repaint();
          }
          try
          {
              Thread.sleep(delay);
          }
          catch(InterruptedException e){System.err.println("Interrupted.");}
      }
      stop();
  }
  
  public void update(Graphics g)
  {   
      Graphics buffer;
      Image offscreen = null;
  
      offscreen = createImage(bound_x, bound_y);
      buffer = offscreen.getGraphics();
      buffer.setColor(getBackground());
      buffer.fillRect(0,0,bound_x, bound_y);
      //update
  
      previouslocation = new Point(currentlocation);
      currentlocation = nextlocation;
  
      //draw
      buffer.setColor(Color.black);
      buffer.drawOval(nextlocation.x, nextlocation.y, size, size);
      buffer.fillOval(nextlocation.x, nextlocation.y, size, size);
  
      //draw rectangles out of vector     
      g.drawImage(offscreen, 0,0, null);
      paint(buffer);
  }   
  
  //class to handle animations
  class Ball extends Canvas 
  {
      public void move()
      {
          nextlocation = new Point(currentlocation.x+dx, currentlocation.y+dy);
          //if it will hit the right or left, flip the x direction and set it 
          if (nextlocation.x+size &gt;= bound_x || nextlocation.x &lt;= 0)
          { dx *= -1; }
          nextlocation.x += dx;
          //if it will hit the top or bottom, flip the y direction and set it
          if (nextlocation.y+size &gt;= bound_y + 100 || nextlocation.y &lt;= 0)
          { dy *= -1; }
          nextlocation.y += dy;
          setBounds(dx,dy,size,size);
          System.out.println(dx + "," + dy);
      }   
  
      public void paint(Graphics g)
      {
          super.paint(g);
          g.setColor(Color.black);
          g.drawOval(0, 0, size, size);
      }
  }
  
      public void actionPerformed(ActionEvent e)
      {
          Object source = e.getSource();
          if (source == this.runbutton)
          {
              running = true;
          }
          else if (source == this.pausebutton)
          {
              running = false;
          }
          else if (source == this.quitbutton)
          {
              //kill processes
              kill = true;
              //remove listeners
              stop();
          }
      }
  
      public void adjustmentValueChanged(AdjustmentEvent e)
      {
          Object source = e.getSource();
          //set the new size. 
          if (source == sizebar)
          {
              //check for clipping
              int newsize = sizebar.getValue();
  
              // x
              if (currentlocation.x+newsize &gt;= bound_x)
              { 
                  newsize = bound_x - currentlocation.x - 1;
                  sizebar.setValue(newsize);
              }
  
              // y
              if (currentlocation.y+newsize &gt;= bound_y + 100)
              {
                  newsize = bound_y+100 - currentlocation.y - 1;
                  sizebar.setValue(newsize);
              }
              size = newsize;
          }
          if (source == speedbar)
          {
              speed = speedbar.getValue();
              delay = MAXSPEED - speedbar.getValue();
          }
      }
  
      public void stop()
      {
          this.speedbar.removeAdjustmentListener(this);
          this.runbutton.removeActionListener(this);
          this.pausebutton.removeActionListener(this);
          this.sizebar.removeAdjustmentListener(this);
          this.quitbutton.removeActionListener(this);
          Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
      }
  }
  </code></pre>