Hello Members,

I have a program (from Deitel Java Solution Manual) which bounces a ball using a Java thread inside a JPanel(which is inside a JFrame). When I made a custom class for the ball, the program is not painting anything on the JPanel.I would appreciate any help.

Following are my programs:

Ball.java:

import java.awt.event.*; 
import javax.swing.*; 
import java.awt.*; 
import java.lang.Thread; 


public class Ball extends JPanel implements Runnable 
{ 
    private boolean xUp, yUp, xUp1, yUp1; 
    private int x, y, xDx, yDy; 
    private final int MAX_X = 500, MAX_Y = 500; 
    private boolean flag = true; 
    private String color; 
    private Thread ball; 

    public Ball(int xCoordinate, int yCoordinate, String color) 
    { 
        x = xCoordinate; 
        y = yCoordinate; 
        color = color; 

        xUp = false; 
        yUp = false; 
        xDx = 1; 
        yDy = 1; 

        ball = new Thread(this); 
        ball.start(); 
    } 


    public void paintBall( Graphics g ) 
    { 
        super.paintComponent( g ); 
        g.setColor( Color.red ); 
        g.fillOval( x, y, 50, 50 ); 

    } 

    public void run() 
    { 
        while ( flag == true ) 
        { 
            try 
            { 
            ball.sleep(10); 
            } 
            catch ( InterruptedException exception ) 
            { 
            System.err.println( exception.toString() ); 
            } 


            if ( y <= 0 ) { 
            yUp = true; 
            yDy = ( int ) ( Math.random() * 5 + 2 ); 
            } 


            else if ( y >= MAX_Y - 50 ) { 
            yDy = ( int ) ( Math.random() * 5 + 2 ); 
            yUp = false; 
            } 


            if ( x <= 0 ) { 
            xUp = true; 
            xDx = ( int ) ( Math.random() * 5 + 2 ); 
            } 


            else if ( x >= MAX_X - 50 ) { 
            xUp = false; 
            xDx = ( int ) ( Math.random() * 5 + 2 ); 
            } 




            if ( xUp == true ) 
            x += xDx; 
            else 
            x -= xDx; 


            if ( yUp == true ) 
            y += yDy; 
            else 
            y -= yDy; 


            repaint(); 
        } 
    } 
} 


The Java Frame:

//Source: Java Textbook (Deitel and Deitel) - Seventh Edition – Solution Manual, Chapter 16, Problem #23.8, Page 1118 
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import java.lang.Thread; 


public class Ball_Bounce extends JFrame 
{ 
    private Thread blueBall, redBall; 
    private boolean xUp, yUp, xUp1, yUp1; 
    private int x, y, xDx, yDy; 
    private final int MAX_X = 500, MAX_Y = 500; 
    private boolean flag = true; 
    private Ball ball; 


    public Ball_Bounce() 
    { 
        createBall(); 

        add (ball); 
        setSize (500,500); 
        setVisible(true); 


    } 

    public void createBall() 
    { 
        ball = new Ball( 300, 250, "red" ); 
    } 


    public static void main (String args []) 
    { 
        new Ball_Bounce(); 
    } 
} 

program is not painting anything

What method does the drawing of the ball? Is that method being called? Add a println to print a message to show that it is called.
What code calls the method where the ball is drawn?

Calling the repaint() method asks the jvm to schedule a call to the paintComponent() method. Where have you coded a paintComponent() method that can be called by the jvm after a call to repaint()?

Hello NormR1,

That was silly of me! Thank you.

Regards

Hello,

If you don't mind, I have a follow-up question:

I re-wrote the above program as below. I can see both the balls bouncing but they are both colored blue instead of red and blue as it is specified in the paintComponent() method of "Ball_Bounce.java". The program works if I remove the "for" loop in the paintComponent() and manually set the color for each cell and paint the balls. I am unable to figure out why the "for" loop makes the difference for the coloring of the balls. I would appreciate any help.

Ball.java: //Source: Java Textbook (Deitel and Deitel) - Seventh Edition – Instructor's Manual, Chapter 16, Problem #23.8, Page 1118

    import java.awt.event.*; 
    import javax.swing.*; 
    import java.awt.*; 
    import java.lang.Thread; 


    public class Ball implements Runnable
    { 
        private boolean xUp, yUp, xUp1, yUp1; 
        private int x, y, xDx, yDy; 
        private final int MAX_X = 500, MAX_Y = 500; 
        private boolean flag = true; 
        private String color; 
        private static Thread ball; 



         public  Ball(int xCoordinate, int yCoordinate) 
        { 
            x = xCoordinate; 
            y = yCoordinate; 
            color = color; 

            xUp = false; 
            yUp = false; 
            xDx = 1; 
            yDy = 1; 

            ball = new Thread(this); 
            ball.start(); 

        } 


        public int getX()
        {
            return x;
        }

        public int getY()
        {
            return y;
        }

        public void run() 
        { 
            while ( flag == true ) 
            { 
                try 
                { 
                ball.sleep(20); 
                } 
                catch ( InterruptedException exception ) 
                { 
                System.err.println( exception.toString() ); 
                } 


                if ( y <= 0 ) { 
                yUp = true; 
                yDy = ( int ) ( Math.random() * 5 + 2 ); 
                } 


                else if ( y >= MAX_Y - 50 ) { 
                yDy = ( int ) ( Math.random() * 5 + 2 ); 
                yUp = false; 
                } 


                if ( x <= 0 ) { 
                xUp = true; 
                xDx = ( int ) ( Math.random() * 5 + 2 ); 
                } 


                else if ( x >= MAX_X - 50 ) { 
                xUp = false; 
                xDx = ( int ) ( Math.random() * 5 + 2 ); 
                } 




                if ( xUp == true ) 
                x += xDx; 
                else 
                x -= xDx; 


                if ( yUp == true ) 
                y += yDy; 
                else 
                y -= yDy; 



            } 
        } 

    } 


    Ball_Bounce.java:


    import java.awt.*; 
    import java.awt.event.*; 
    import javax.swing.*; 
    import java.lang.Thread; 


    public class Ball_Bounce extends JPanel implements ActionListener
    { 
        private Ball ball[] = new Ball[2]; 
        private Timer timer;

        public Ball_Bounce() 
        { 
            timer = new Timer (20, this);
            timer.start();
            ball[0] = new Ball( 300, 250); 
            ball[1] = new Ball (450, 450);

        } 

        public void actionPerformed (ActionEvent e)
        {
            repaint();
        }

      public void paintComponent( Graphics g ) 
        { 
           super.paintComponent(g); 


           for (int i = 0; i < 2; i++)
           {
                Color c = new Color (100, 0, 0);  
                g.setColor (c);
                g.fillOval( ball[i].getX(), ball[i].getY(), 50, 50 ); 
                c = new Color (0, 0, 100);  
                g.setColor (c);
                g.fillOval( ball[i].getX(), ball[i].getY(), 50, 50 );
           }

        }


        public static void main (String args []) 
        {    
            JFrame f = new JFrame ("Bouncing Ball");
            Ball_Bounce b = new Ball_Bounce ();
            f.add (b); 
            f.setSize (500,500); 
            f.setVisible(true); 
        }

    } 

lines 141, 144 paint exactly the same oval, so first you paint it in red, but them immediately overpaint that with blue. I wold like to sugest a better approach, but that would probably conflict with the book you are using.

James:
Thank you for the reply. I am eager to hear about your approach. If you could, kindly let me know.

Thank you!

If there are only two balls and they are at different locations, then you need to paint each ball at its own location. You could remove the loop and draw each ball (ball[0] and ball[1]) separately at its own location. The existing loop draws the two balls at the same location.

NormR1,

I realized that after James's message. Thank you!

If I have to handle multiple balls, is there a better strategy?

Thank you!

Yes, there's a pretty standard way of doing it. One Timer that calls each Ball's method to update its posiiton at regular intervals, and paintComponent delegates painting to a method in each Ball. Here's a little runnable tutorial program that shows the principles in action.

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.TimerTask;
import javax.swing.*;

public class Animation1 extends JPanel {
   // Basic architecture demo for multi-sprite animation

   public static void main(String[] args) {
      // create and display the animation in a JFrame
      final JFrame frame = new JFrame("Animation 1 (close window to exit)");
      Animation1 animationPanel = new Animation1(600, 400);
      frame.add(animationPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }

   private ArrayList<SimpleSprite> sprites = new ArrayList<SimpleSprite>();

   final static int TIMER_MSEC = 30; // mSec per clock tick

   Animation1(int width, int height) {
      setPreferredSize(new Dimension(width, height));
      sprites.add(new SimpleSprite(Color.blue, 0, 35, 2, 1));
      sprites.add(new SimpleSprite(Color.red, 0, 250, 2, -1));
      startTimer();
   }

   void startTimer() {
      // use java.util Timer rather than javax.swing Timer
      // to avoid running intensive simulation code on the swing thread
      java.util.Timer timer = new java.util.Timer();
      TimerTask timerTask = new TimerTask() {
         @Override
         public void run() {
            updateSimulation();
         }
      };
      timer.scheduleAtFixedRate(timerTask, 0, TIMER_MSEC);
   }

   public void updateSimulation() {
      // called by Timer every 50 milliseconds
      for (SimpleSprite s : sprites) {
         s.update(); // update position of the sprite
      }
      repaint(); // request Swing to schedule re-paint of screen
   }

   @Override
   public void paintComponent(Graphics g) {
      // screen refresh - called by Swing as needed
      Graphics2D g2d = (Graphics2D) g;
      paintBackground(g2d);
      for (SimpleSprite s : sprites) {
         s.draw(g2d);// draw the sprite at latest positions
      }
   }

   void paintBackground(Graphics2D g2d) {
      // could be an image file etc, this is just plain grey
      g2d.setColor(Color.LIGHT_GRAY);
      g2d.fillRect(0, 0, getWidth(), getHeight());
   }



}

class SimpleSprite {
   // basic x,y movement at constant velocity

   float x, y, dx, dy; // position and velocity (pixels/TIMER_MSEC)
   Color color;

   public SimpleSprite(Color color, float x, float y, float dx, float dy) {
      // initial position and velocity
      this.color = color;
      this.x = x;
      this.y = y;
      this.dx = dx;
      this.dy = dy;
   }

   public void update() { // update position and velocity every n milliSec
      x += dx; // velocity in x direction
      y += dy; // velocity in y direction
   }

   public void draw(Graphics2D g2d) {
      g2d.setColor(color);
      g2d.fillOval((int) x, (int) y, 100, 100); // draw object(s) at latest position.
   }

}

Hello James,

Thank you!

Regards

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.