0

I have the typical java assignment - Create a JPanel in a JFrame and have balls bounce around. More specifically, each time the user clicks in the window it should generate a ball (random size/color/direction) with an unlimited # of balls. Oh, and each ball should be running in a thread.

I am using an ArrayList to hold the objects. I have a mouseListener that upon a click, instantiates a new ball object. I then create a new thread with that object and call start on it. This all seems to work fine. I put "dummy" JOptionPane pop-ups in various areas to confirm my code was getting there and it appears it is all executing, but no balls ever get drawn, much less drawn over and over to make them move and bounce around the screen.

Any input or suggestions would be much appreciated.

   import java.util.Random;
    import java.util.ArrayList;
    import java.awt.*;
    import javax.swing.*;
    import java.awt.Color;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;

    public class BouncingBalls extends JFrame
    {
       private JPanel ballPrison;
       private Random generator = new Random();
       private Color bgColor = Color.WHITE;
       ArrayList<Balls> ballsList = new ArrayList<Balls>();
       private Color ballColor;
       private int ballSize;
       private int ballCoordinateX;
       private int ballCoordinateY;
       private int ballDirectionX;
       private int ballDirectionY;

       public BouncingBalls()
       {
          super("Bouncing Balls");

      ballPrison = new JPanel();
      ballPrison.setBackground(bgColor);
      add(ballPrison);

      ballPrison.addMouseListener(new MouseAdapter() {
         public void mouseClicked(MouseEvent event)
         {
            JOptionPane.showMessageDialog (BouncingBalls.this, "Click at " + event.getX() + "," + event.getY(), "Click Registered", JOptionPane.INFORMATION_MESSAGE);
            ballsList.add(new Balls(event.getX(), event.getY()));
            Thread t = new Thread(ballsList.get(ballsList.size() - 1));
            t.start();
         }
      } );

   }



   private class DrawJPanel extends JPanel
   {
      public void paintComponent(Graphics g)
      {
         super.paintComponent(g);
         this.setBackground(bgColor);
         g.setColor(ballColor);
         g.fillOval(ballCoordinateX, ballCoordinateY, ballSize, ballSize);
      }
  }


   private class Balls implements Runnable
   {

      public Balls(int x, int y)
      {
         ballColor = new Color(generator.nextInt(256),generator.nextInt(256),
            generator.nextInt(256));
         ballSize = generator.nextInt(20) + 5;
         ballCoordinateX = x;
         ballCoordinateY = y;
         ballDirectionX = generator.nextInt(8) + 3;
         ballDirectionY = generator.nextInt(8) + 3;
      }

      public void run()
      {
/*         JOptionPane.showMessageDialog (BouncingBalls.this,
            "ballColor = " + ballColor + "\nballSize = " + ballSize + "\nCoordinates = " + ballCoordinateX + "," +
            ballCoordinateY + "\nDirections = " + ballDirectionX + "," + ballDirectionX,
            "Click Registered", JOptionPane.INFORMATION_MESSAGE);
*/
         while(true)
         {
            move();
            repaint();

         }
      }

      public void move()
      {
            if (ballCoordinateX + ballDirectionX < 0) {
               ballDirectionX = ballDirectionX;
            } else if (ballCoordinateX + ballDirectionX > getWidth() - ballSize) {
               ballDirectionX = -(ballDirectionX);
            } else if (ballCoordinateY + ballDirectionY < 0) {
               ballDirectionY = ballDirectionY;
            } else if (ballCoordinateY + ballDirectionY > getHeight() - ballSize) {
               ballDirectionY = -(ballDirectionY);
            }

            ballCoordinateX = ballCoordinateX + ballDirectionX;
            ballCoordinateY = ballCoordinateY + ballDirectionY;
      }
   }



   public static void main (String args[])
   {
      BouncingBalls ballBox = new BouncingBalls();

      ballBox.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      ballBox.setSize(500, 500);
      ballBox.setLocationRelativeTo(null);
      ballBox.setVisible(true);
   }
}
HaveNoDisplayName
  • 8,291
  • 106
  • 37
  • 47
  • What's actually painting the balls? Also, having a `Thread` for each ball with greatly degrade performance as you add more balls. A better solution would be to use a single thread and iterate over the list of the available balls and update them. For [example](http://stackoverflow.com/questions/13022754/java-bouncing-ball/13022788#13022788) – MadProgrammer Nov 09 '15 at 00:59
  • @MadProgrammer, why have even one background thread? Why not use one or more Timers to drive the animation? – Solomon Slow Nov 09 '15 at 02:39
  • @jameslarge It comes down to requirements, but if you're using more then one `Timer`, you'll run into the same performance issues (not to mention out of sync updates) – MadProgrammer Nov 09 '15 at 02:41
  • The only method I see that does any drawing is `paintComponent(g)` in `DrawJPanel`, but where is `DrawJPanel` used? – Solomon Slow Nov 09 '15 at 02:43
  • I don't have a lot of Swing experience, but are you sure you're allowed to call `repaint()` from any arbitrary thread? Most Swing methods should only be called from the Event Dispatch Thread (i.e., from within an event handler, or by using `SwingUtilites.invokeLater(r)`. – Solomon Slow Nov 09 '15 at 02:46
  • Thanks for the input so far. As for using multiple threads, that's part of the assignment. It's not necessarily to be the most efficient program as it is to practice using multiple threads for the first time. However, since we've only done a few things with Graphics, that seems to be what's giving me the most issues. @jameslarge I believe you're correct that I can't arbitrarily call repaint from anywhere... Yet I can't figure out how/where to call repaint on each independent ball so that multiple balls are continually moving and everything is continually being repainted... – hollywoodfrodo Nov 10 '15 at 03:58
  • One solution could be to use however many threads you need to drive the physics simulation, and use a `javax.swing.Timer` to periodically grab a snapshot of the model and update the window. – Solomon Slow Nov 10 '15 at 13:57

0 Answers0